House Prices Solution

这是我第一次完整的数据分析实战。以下是我对这一过程的完整记录。
比赛地址:https://www.kaggle.com/c/house-prices-advanced-regression-techniques

首先导入所需要用到的库

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy.stats import norm
from scipy.special import boxcox1p
from scipy.stats import boxcox_normmax
from sklearn.preprocessing import StandardScaler
from scipy import stats

导入数据

train = pd.read_csv('/Users/mac/Desktop/Data/house-prices-advanced-regression-techniques/train.csv')
test = pd.read_csv('/Users/mac/Desktop/Data/house-prices-advanced-regression-techniques/test.csv')

将特征与标签分离

train_ID = train['Id']
test_ID = test['Id']
train.drop('Id',axis=1,inplace=True)
test.drop('Id',axis=1,inplace=True)
xtrain = train.iloc[:,:-1]
ytrain = train.iloc[:,-1]
ntrain = train.shape[0]
ntest = test.shape[0]

接下来考虑是否要将训练集与测试集进行合并(便于对特征进行处理),若需要使用算法对缺失值进行填补则尽量将训练集与测试集分开。

all_data = pd.concat([xtrain,test])

对缺失值进行分析和处理

all_data.isnull().sum().sort_values(ascending=False)

对含有缺失值的特征进行查看

all_data['PoolQC'].unique()

PoolQC表示泳池质量,查看数据描述可知Na值表示无泳池。
用None填补。

all_data['PoolQC'] = all_data['PoolQC'].fillna('None')

其余Na值表示为None的都用None填补

all_data["MiscFeature"] = all_data["MiscFeature"].fillna("None")
all_data["Alley"] = all_data["Alley"].fillna("None")
all_data["Fence"] = all_data["Fence"].fillna("None")
all_data["FireplaceQu"] = all_data["FireplaceQu"].fillna("None")

继续查看其余特征

all_data['LotFrontage'].unique()

该特征缺失值可使用最近‘Neighborhood’的值填补

all_data["LotFrontage"] = all_data.groupby("Neighborhood")["LotFrontage"].transform(lambda x: x.fillna(x.median()))

发现有多个与garage相关的特征,可一起处理

for col in ('GarageType', 'GarageFinish', 'GarageQual', 'GarageCond'):
    all_data[col] = all_data[col].fillna('None')
for col in ('GarageYrBlt', 'GarageArea', 'GarageCars'):
    all_data[col] = all_data[col].fillna(0)

将与basement相关的特征一起处理

for col in ('BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF','TotalBsmtSF', 'BsmtFullBath', 'BsmtHalfBath'):
    all_data[col] = all_data[col].fillna(0)
for col in ('BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2'):
    all_data[col] = all_data[col].fillna('None')

与MasVnrType(表层砌体类型)相关的缺失值文档中无描述,但缺失值较少可使用None来替代

all_data["MasVnrType"] = all_data["MasVnrType"].fillna("None")
all_data["MasVnrArea"] = all_data["MasVnrArea"].fillna(0)

MSZoning等缺失值较少的特征都使用众数填补

for i in ['MSZoning','Functional','Utilities','SaleType','Exterior1st','Electrical','Exterior2nd','KitchenQual']:
    all_data[i] = all_data[i].fillna(all_data[i].mode()[0])

查看是否还存在缺失值

all_data.isnull().sum().sum()

对于时间类特征我们需要进行特殊处理。
YearBuilt与YearRemodAdd有重复,所以删除YearBuilt。

all_data = all_data.drop('YearBuilt',axis=1)

YrSold与YearRemodAdd,GarageYrBlt与YrSold相减可创造出新特征

all_data['yrgap'] = all_data['YrSold']-all_data['YearRemodAdd']
all_data = all_data.drop('YearRemodAdd',axis=1)
all_data['Garyrgap'] =  all_data['YrSold']-all_data['GarageYrBlt']
all_data = all_data.drop('GarageYrBlt',axis=1)

数据无量纲化
首先要将类别型数据与连续型数据分离
首先做一个初步筛选,认为特征数据种类不足20种的都为类别型变量。

qualitative = []
for i in train.columns:
    if train[i].unique().shape[0] < 20:
        qualitative.append(i)

由于种类过多,就不一一分析。
类别型变量中许多值的type为‘int’,‘float’,将其转换为’object‘

for i in qualitative:
    if train[i].dtype == 'int' or 'float':
        train[i] = train[i].astype('str')

再取出连续性数据

quantitative = [f for f in train.columns if train[f].dtype!='object']
#这种写法更简单

对连续型数据进行数据标准化

all_data[quantitative] = StandardScaler().fit_transform(all_data[quantitative])

在对类别型数据进行独热编码

all_data = pd.get_dummies(all_data)

分析标签

sns.distplot(ytrain)

在这里插入图片描述
标签呈偏态分布,利用np.log1p进行处理

ytrain = np.log1p(ytrain)

在这里插入图片描述
导入建模、调参需要的库

import xgboost as xgb
from sklearn.model_selection import GridSearchCV

对数据进行最后一步处理

for i in all_data.columns:
    if all_data[i].dtype == 'object':
        all_data[i] = all_data[i].astype('float')
xtrain = all_data[:ntrain]
test = all_data[ntrain:]

建模
cv_params为需要进行网格搜索的参数,other_params为以确定参数

cv_params = {'booster':['gbtree','dart'],'n_estimators':[250,320,400,500],'learning_rate': [0.05,0.1,0.2,0.3,0.4]}
other_params = {'learning_rate': 0.1, 'n_estimators': 320, 'max_depth': 5, 'min_child_weight': 1.7817, 'seed': 0,
                    'subsample': 0.83, 'colsample_bytree': 0.8, 'gamma': 0.03, 'reg_alpha': 0, 'reg_lambda': 1,'booster':'gbtree'
               ,'random_state':7}
model = xgb.XGBRegressor(**other_params)
optimized_GBM = GridSearchCV(estimator=model, param_grid=cv_params,cv=5,scoring='neg_mean_squared_error', verbose=1, n_jobs=4)
optimized_GBM.fit(xtrain, ytrain)

#print('每轮迭代运行结果:{0}'.format(evalute_result))
print('参数的最佳取值:{0}'.format(optimized_GBM.best_params_))
print('最佳模型得分:{0}'.format(-optimized_GBM.best_score_))

由于特征过多网格搜索可能会很慢,可以先设定一组参数。

n_folds = 5

def rmsle_cv(model):
    kf = KFold(n_folds, shuffle=True, random_state=42).get_n_splits(train.values)
    rmse= np.sqrt(-cross_val_score(model, xtrain, ytrain, scoring="neg_mean_squared_error", cv = kf))
    return(rmse)
model_xgb = xgb.XGBRegressor(colsample_bytree=0.4603, gamma=0.0468, 
                             learning_rate=0.05, max_depth=3, 
                             min_child_weight=1.7817, n_estimators=2200,
                             reg_alpha=0.4640, reg_lambda=0.8571,
                             subsample=0.5213, silent=1,
                             random_state =7, nthread = -1)
score = rmsle_cv(model_xgb)
print("Xgboost score: {:.4f} ({:.4f})\n".format(score.mean(), score.std()))

这样得到了第一次建模的得分。
再进行特征选择(这一步可在第一次建模前就进行)

from sklearn.feature_selection import RFE
from sklearn.model_selection import cross_val_score
scores = []
for i in range(100,131,10):
    selector = RFE(model_xgb,n_features_to_select=i,step=30).fit(xtrain,ytrain)
    X_wrapper = selector.transform(xtrain)
    score = cross_val_score(model_xgb,X_wrapper,ytrain,cv=5,scoring="neg_mean_squared_error").mean()
    scores.append(score)
plt.plot(range(100,131,10),scores)
plt.show()

通过调整n_features_to_select寻找最合适的特征数量
确定好后提取出特征名

selector = RFE(model_xgb,n_features_to_select=100,step=30).fit(xtrain,ytrain)
X_wrapper = selector.transform(xtrain)
fea_sel = []
for i in range(xtrain.columns.shape[0]):
    if selector.support_[i]==True:
        fea_sel.append(xtrain.columns[i])
fea_sel

必须确保测试集与训练集的特征相同

test = test[fea_sel]

最后就是利用网格搜索进行无数次的调参。
我最高的得分0.125,希望这个分享对大家有帮助。
在查看数据量不是特别大的数据集时可以尝试使用pandas_profiling生成报告。这会剩下很多的代码工作量。
其实在数据预处理的环节应该还要再加上清理异常值的过程,但我还不会…so…到这结束了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值