房价预测案例
检视源数据集
import numpy as np
import pandas as pd
读入数据
- 一般来说index那一栏没有什么用,我们用来作为我们pandas dataframe的index。这样以后要是检索起来也很方便
- Kaggle上默认数据放在input文件夹下。
train_df=pa.read_csv('../input/train.csv',index_col=0)
test_df=pd.read_csv('../input/test.csv',index_col=0)
检视数据源
train_df.head()
pandas默认给出前五行
NAN不考虑
文本转化为数字
step 2 合并数据
将train集和test集合并起来,这么做主要是为了用DF进行数据预处理的时候回方便。等所有的需要的预处理进行完成后,我们再把他们分开
首先,SalePrice作为我们的训练目标,只会出现在训练集中,不会出现在测试集中。所以,我们先把SalePrice这一列拿出来。
我们先看一下SalePrice长什么样子
%matplotlib inline
prices=pd.DataFrame({"price":train_df['SalePrice'],"log(price+1)":np.loglp(train_df["SalePrice"]})
prices.hist()
可见,我们的label本身并不平滑(分布为高斯分布)。为了我们分类器的学习更加准确,我们会把label给“平滑掉”(正态化)(回归问题需要平滑,分类问题不需要平滑)。
这一步大多数同学都会Miss掉,导致自己的结果总是达不到一定标准。
这里我们使用log1p,也就是log(X+1)(防止x为0),避免了复值的问题。
如果我们这里把数据都给平滑化了,那么最后算结果的时候,得把预测到的平滑数据变回去。
按照“怎么来的就怎么回去”原则,log1p()就需要expm1();同理,log()就需要exp()
y_train=np.log1p(train_df.pop["SalePrice"])
然后我们把剩下的部分合并起来
all_df=np.contact((train_df,test_df),axis=0)
all_df.shape()
y_train是“SalePrice”那一列
y_train.head()
step3 变量转化
类似特征工程,就是把不方便处理或者不unify的数据给统一了。
正确化变量属性
首先,我们注意到,MSSubClass的值其实是一个category(无数值大小之分),
使用DF时,这类数字会被默认记成数字。
这种东西很有误导性,我们需要把它变回成string。
all_df["MSSubClass"].dtypes
all_df["MSSubClass"]=all_df["MSSubClass"].astype("str")
变成string之后,做个统计就很清楚了。
all_df["MSSubClass"].value_counts()
把category的变量转变成numerical表达形式
当我们用numerical来表达categorical的时候,要注意,数字本身有大小的含义,所以乱用数字后给模型学习带来麻烦。于是我们用one-hot的方法表达category。
pandas自带的get_dummies方法,可以帮你一键做到one-hot。
pd.get_dummies(all_df["MSSubClass"],prefix='MSSubClass').head()
此刻MSSubClass就被分成12个column,每一个代表一个category。是就是1,不是就是0。
同理,我们把所有的category数据,都给one-hot了。
all_dummy_df=pd.get_dummies(all_df)%自动选取category的拓展
all_dummy_df.head()
处理好numerical变量
就算是numerical变量,也是有一些小问题,
比如,有一些数据是缺失的
all_dummy_df.isnull().sum().sort_values(ascending=False).head()
处理这些缺失信息,得靠审题。一般来说,数据集的描述里会写的很清楚,这些缺失值都代表什么。当然,如果实在没有的话,也只能靠自己的“想当然”。
在这里,我们用平均值(0,中位数,最大值,最小值)来填满这些空缺。
mean_cols=all_dummy_df.mean()
mean_cols.head(10)
all_dummy_df=all_dummy_df.fillna(mean_cols)
看看是不是没空缺了。
NAN表示空缺
all_dummy_df.isnull().sum().sum()
标准化numerical数据
这一步并不是必须的,但是得看你想要用的分类器是什么。一般来说,regression的分类器都比较傲娇,最好是把源数据都放在一个标准分布内。不要让数据间的差距太大。
这里我们当然不需要吧One-Hot的那些0/1给标准化了。我们的目标是那些本来就是numerical的数据:
先来看看哪些本身是numerical的:
numeric_cols=all_df.columns[all_df.dtypes!='object']
numeric_cols
计算标准分布:(X-X‘)/s
让我们的数据点更加平滑,更便于计算。
注意:这里也可以使用log。
numeric_cols_means=all_dummy_df.loc[:,numeric_cols].mean()
numeric_cols_std=all_dummy_df.loc[:,numeric_cols].std()
all_dummy_df.loc[:,numeric_cols]=(all_dummy_df.loc[:,numeric_cols]-numeric_cols_means)/numeric_cols_std
step 4 建立模型
把数据分回训练/测试集
bummy_train_df=all_dummy_df.loc[train_df.index]
bummy_test_df=all_dummy_df.loc[test_df.index]
bummy_train_df.shape,dummy_test_df.shape
Ridge Reggression
用ridge reggression模型来跑一遍看看。(对于多因子的数据集,这种模型可以方便的把所有的var都无脑的放进去)
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score
这一步不是很有必要,只要把DF转化成Numpy Array,这跟Sklearn更加匹配。
X_train=bummy_train_df.values
X_test=bummy_test_df.values
用sklearn自带的cross validation(可以减少数据中噪声的影响)方法来测试模型
for alpha in alphas:
clf=Ridge(alpha)
test_score=np.sqrt(-cross_val_score(clf,X_train,y_train,cv=10,scoring="neg_mean_squared_error"))
test_scores.append(np.mean(test_score))
存下所有的CV值,看那个更好(也就是调参数)
import matplotlib.pyplot as plt
plt.plot(alphas,test_scores)
plt.title("Alpha vs cv Error")
Random Forest
from sklearn.ensemble import RandomForestReggressor
max_featrues=[.1,.3,.5,.7,.9,.99]%每棵树看到的特征占总特征的比例
test_scores=[]
for max_feat in max_featrues:
clf=RandomForestReggressor(n_estimator=200,max_features,max_feat)
test_score=np.sqrt(-cross_val_score(clf,X_train,y_train,cv=5,score="neg_mean_squared_error"))
test_scores.append(np.mean(test_score))
plt.plot(max_featrues,test_scores)
plt.title("Max Featrues vs cv Error")
step 5:Ensemble
这里我们用一个Stacking的思维来汲取两种或者多种模型的优点
首先,我们把最好的parameter拿出来,做成我们最终的model
ridge=Ridge(alpha=15)
rf=RandomForestReggressor(n_estimators=500,max_features=.3)
ridge.fix(X_train,y_train)
rf.fix(X_train,y_train)
上面提到了,因为最前面我们给label做了个log(1+x),于是我们要把predict的值给exp回去,并且减掉“1”
所以就是我们的expm1()函数
y_rigde=np.expm1(ridge.predict(X_test))
y_rf=np.expm1(rf.predict(X_test))
一个正经的Ensemble是把这群model的的预测结果作为新的input,再做一次预测。这里我们简单的方法,就是直接平均化。
y_final=(y_ridge+y_rf)/2
step 6:提交结果
submission_df=pd.dataFrame(da={'Id':test_df.index,'SalePrice':y_final})
房价预测进阶版
前面的特征工程没有改动,重点在后面的模型Ensemble
高级的Ensemble
一般来说,单个分类器的效果真的是很有限的。我们会倾向于把N多的分类器和在一起,做一个“综合分类器”以达到最好的效果。
我们从刚刚的实验中得知,Ridge(alpha=15)给了我们最好的结果
from sklearn.linear_model import Ridge
ridge=Ridge(15)
Bagging
Bagging把很多的小分类器放在一起,每个train随机的一部分数据,然后把他们最终的结果综合起来(多数投票机制)。
Sklearn已经直接提供了这套架构,我们直接调用:
from sklearn.ensemble import BaggingRegrssor%分为BaggingRegrssor,%BaggingClassifier
from sklearn.model_selection import cross_val_score
在这里,我们用CV结果来测试不同的分类器个数对最后结果的影响。
注意,我们Bagging部署的时候,要把它的函数base_estimator里填上你的小分类器(ridge)
params=[1,10,15,20,25,30,40]
test_scores=[]
for param in params:
clf=BaggingRegressor(n_estimators=param,base_estimator=ridge)
test_score=np.sqrt(-cross_val_score(clf,X_train,y_train,cv=10,scoring="neg_mean_squared_error"))
test_scores.append(np.mean(test_score))
import matplotlib.pyplot as plt
plt.plot(params,test_scores)
plt.title("n_estimators vs cv Error")
如果你并没有提亲测试过ridge模型,你也可以用Bagging自带的DecisionTree模型。
代码一样,就是把base_estimator删去。
Boosting
Boosting理论上比Bagging更高级一点,它也是揽一把分类器。但是把他们线性排列。下一个分类器把上一个分类器分类不好的地方加上更高的权重,这样下一个分类器就能在这个部分学习的更深刻。
from sklearn.ensemble import AdaBoostRegressor
test_scores=[]
params=[10,15,20,25,30,40]
for param in params:
clf=BaggingRegressor(n_estimators=param,base_estimator=ridge)
test_score=np.sqrt(-cross_val_score(clf,X_train,y_train,cv=10,scoring="neg_mean_squared_error"))
test_scores.append(np.mean(test_score))
plt.plot(params,test_scores)
plt.title("n_estimators vs cv Error")
不稳定,可以调更小的cv。希望为个V型
也可以使用AdaBoost自带的DecisionTree。
XGBoost
from xgboost import XGBRegressor
使用sklearn自带的cross validation方法来测试模型
params=[1,2,3,4,5,6]
test_scores=[]
for param in params:
clf=XGBRegressor(max_depth=param)
test_score=np.sqrt(-cross_val_score(clf,X_train,y_train,cv=10,scoring="neg_mean_squared_error"))
test_scores.append(np.mean(test_score))
plt.plot(params,test_scores)
plt.title("n_estimators vs cv Error")