资讯专栏INFORMATION COLUMN

Kaggle入门级赛题:房价预测——数据挖掘篇

joyqi / 3307人阅读

摘要:到这里,我们经过以上步骤处理过的数据,就可以喂给分类器进行训练了。一般来说,单个分类器的效果有限。我们会倾向于把多个分类器合在一起,做一个综合分类器以达到最好的效果。比理论上更高级点,它也是揽来一把的分类器。

特征工程

我们注意到 MSSubClass 其实是一个 category 的值:

all_df["MSSubClass"].dtypes

有:

dtype("int64")

它不应该做为数值型的值进行统计。因此,进行强制类型转换,把它变回 string

df["MSSubClass"] =df["MSSubClass"].astype(str) 

然后,统计其出现频次:

all_df["MSSubClass"].value_counts()

就很清楚的了解 MSSubClass 特征了。

当我们用 numerical 来表达 categorical 的时候要注意,数字本身有大小的含义,所以乱用数字会给之后的模型学习带来麻烦。这里我们可以用 One-Hot 的方法来表达 category

pandas 自带的get_dummies方法,可以做到一键 One-Hot

pd.get_dummies(df["MSSubClass"], prefix="MSSubClass").head()

效果如下:

此时,MSSubClass 被我们分成了 12 列,每列代表一个 category,是为 1,否为 0。

所以,同理。接下来,我们需要把所有的 category 数据全部一键 One-Hot

all_dummy_df = pd.get_dummies(df)
all_dummy_df.head()

此时,数据长这样子:

接下来,我们来处理 numerical 的数据。

首先查看 One-Hot 后的缺失值:

all_dummy_df.isnull().sum().sort_values(ascending=False).head(10)

我们需要对这些缺失值进行处理,这里采用平均值来填充空缺:

mean_cols = all_dummy_df.mean()
all_dummy_df = all_dummy_df.fillna(mean_cols)

再次查看是否有缺失值:

all_dummy_df.isnull().sum().sum()

显示为 0,即缺失值都已被填充。

到这里,我们经过以上步骤处理过的数据,就可以喂给分类器进行训练了。为了让数据更加规整化,数据间的差距不要太大,在一个标准分布内,也就是数据平滑化。我们对那些本来就是 numerical 的数据进行处理(与 One-Hot 的 0/1 数据不同)。

首先,我们来查看哪些是 numerical 的数据:

numeric_cols = df.columns[df.dtypes != "object"]
numeric_cols

采用公式(X-X")/s,计算标准分布:

numeric_col_means = all_dummy_df.loc[:, numeric_cols].mean()
numeric_col_std = all_dummy_df.loc[:, numeric_cols].std()
all_dummy_df.loc[:, numeric_cols] = (all_dummy_df.loc[:, numeric_cols] - numeric_col_means) / numeric_col_std

得到的数据如下:

all_dummy_df.head()

以上就完成了对数据的处理。

建立模型

首先,把数据集分回训练集和测试集:

dummy_train_df = all_dummy_df.loc[train_df.index]
dummy_test_df = all_dummy_df.loc[test_df.index]

首先采用 Ridge Regression 模型,因为对于多因子的数据集,这种模型可以方便的把所有的变量都一股脑的放进去,我们先用这种模型做实验。

为了更好的使用 Sklearn,我在这里把 DataFrame 转化成 Numpy Array(这一步不是必须):

X_train = dummy_train_df.values
X_test = dummy_test_df.values

把数据放到模型里跑一遍,用 Sklearn 自带的 cross validation 方法来测试模型:

from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score

alphas = np.logspace(-3, 2, 50)
test_scores=[]
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 值,看看哪个 alpha 值更好,也就是我们常说的调参数

plt.plot(alphas, test_scores)
plt.title("Alpha vs CV Error")
plt.xlabel("alpha")
plt.ylabel("CV Error")

可以看到,当 alpha 为 10 到 20 的时候,CV Error 达到最低 0.135 左右。也就是说大约 alpha = 15 的时候给了我们最好的结果。

一般来说,单个分类器的效果有限。我们会倾向于把多个分类器合在一起,做一个“综合分类器”以达到最好的效果。所以接下来我们要做的事就是 ensemble

Ensemble 的方法有 BaggingBoosting 两大类。Bagging 把很多的小分类器放在一起,每个训练随机的一部分数据,然后采用多数投票制把它们的最终结果综合起来。Boosting 比 Bagging 理论上更高级点,它也是揽来一把的分类器。但是把他们线性排列。下一个分类器把上一个分类器分类得不好的地方加上更高的权重,这样下一个分类器就能在这个部分学得更加“深刻”。下面我们分别来看一下。

Bagging

from sklearn.ensemble import BaggingRegressor
from sklearn.model_selection import cross_val_score

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))
    
plt.plot(params, test_scores)
plt.title("n_estimator vs CV Error")

可以看到,我们用 15 个小的 ridge 分类器就达到了 0.134 以下的效果。

Boosting

from sklearn.ensemble import AdaBoostRegressor

params = [10, 15, 20, 25, 30, 35, 40, 45, 50]
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))
    
plt.plot(params, test_scores)
plt.title("n_estimator vs CV Error");

20 个小的 ridge 分类器的效果,达到了 0.133。

最后,祭出 xgboost 大杀器:

from xgboost import XGBRegressor

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("max_depth vs CV Error")

我们看到,当参数为 5 的时候,效果接近 0.125!

提交结果

最后,我们将训练好的模型对数据进行训练:

xgb = XGBRegressor(max_depth=5)
xgb.fit(X_train, y_train)
y_xgb = np.expm1(xgb.predict(X_test))
submission_df = pd.DataFrame(data= {"Id" : test_df.index, "SalePrice": y_xgb})

最终,我们输出的数据长这样子:

submission_df.head()

将它存为.csv文件:

submission_df.to_csv("submission_xgb.csv",index=False)

提交到 kaggle 平台的 Score 是 0.13942,排名在 50% 左右。整个过程没有对特征信息进行太多的处理,还有太多需要改进的地方。

后记

第一次完完整整的从头到尾自己做了一个比赛,还是有太多地方浅浅略过,确实,如果只是调参跑模型的话,应该不是难事,但是如何获得更好的效果,数据量大时现有的程序跑不动,需要改进算法等方面,还有太多值得学习的地方,因为这件事好像没有一个最优结果,只有更优的结果。


不足之处,欢迎指正。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/44998.html

相关文章

  • Kaggle入门赛题房价预测——数据分析

    摘要:本次分享的项目来自的经典赛题房价预测。分为数据分析和数据挖掘两部分介绍。本篇为数据分析篇。赛题解读比赛概述影响房价的因素有很多,在本题的数据集中有个变量几乎描述了爱荷华州艾姆斯住宅的方方面面,要求预测最终的房价。 本次分享的项目来自 Kaggle 的经典赛题:房价预测。分为数据分析和数据挖掘两部分介绍。本篇为数据分析篇。 赛题解读 比赛概述 影响房价的因素有很多,在本题的数据集中有 ...

    sarva 评论0 收藏0
  • 植被类型预测

    摘要:通过海拔坡度到水源的距离地块位置等特征项,对地块植被的类型进行预测个类型。竞赛结果提交请选手利用建立的模型对每阶段提供的预测数据集中的地块植被类型列进行预测类,预测结果按如下格式保存成格式提交。 showImg(https://segmentfault.com/img/bVbjmT7); 参加佛山互联网协会建模大赛,主题为植被类型预测,数据量分3个阶段,10/15/15万左右的放出,暨...

    z2xy 评论0 收藏0
  • Kaggle入门级竞赛top5%排名经验分享】— 建模

    摘要:提取出中的信息特征缺失值同样,观察的缺失值情况缺失值处理发现两位都是女性。特征缺失值特征有的缺失值,较为严重,如果进行大量的填补会引入更多噪声。因为缺失值也是一种值,这里将缺失值视为一种特殊的值来处理,并根据首个字符衍生一个新的特征。 作者:xiaoyu 微信公众号:Python数据科学 知乎:python数据分析师 showImg(https://segmentfault.com/...

    iOS122 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<