在学习完各种高大上的机器学习理论知识(线性回归、逻辑回归、分类决策树、随机森林等等)之后,也许你会问这玩意儿到底有什么用?? 也许你已经按捺不住想自己好奇的心,想找到实际的数据练练手??
Talk is cheap, show me the code!
本篇文章就是用 kaggle 平台上实际的数据带你走进机器学习的世界,来看看,所谓的数据挖掘或者机器学习实际应用到底是怎么样一个过程。
1.数据集介绍
Kaggle 平台上包含9500多个数据集,简直就是我们学习机器学习的一座宝库,本篇文章使用的是爱荷华州艾姆斯的住宅房价数据。
- 问题背景页
- 可下载 Data 的页面
- 内核 kernels ,你会看到各种大神级人物很棒的数据处理合建模idea
- 数据背景
基于竞赛方所提供的爱荷华州埃姆斯的住宅数据信息,预测每间房屋的销售价格,很明显这是一个回归问题。
常用算法: 线性回归、随机森林、GBDT、xgboost、lightGBM
2.如何开始?
当第一次真正对这么复杂的数据进行操作,也许你有点不知所措,别着急待我们一点点分析后,肯定会有大大的收获!!
用机器学习解决问题的一般步骤如下:
在训练模型之前,对数据进行分析探索,找出特征工程属性是非常重要的!!
数据探索
- 总体预览:了解每列数据的含义,数据的格式等;
- 数据初步分析:使用绘图工具初步了解数据之间的相关性,为构造特征工程以及模型建立做准备;
特征工程
- 根据常识以及数据分析的结果构造特征工程;
- 处理缺失值、数据类型转换等;
模型选择
- 根据目标函数确定学习类型,是无监督学习还是监督学习,是分类问题还是回归问题等;
- 选择多个模型进行训练,比较各个模型的分数,然后取效果较好的模型作为基础模型;
模型融合
- 通过对模型的对比打分方式选择合适的模型;
- 在房价预测里我们使用模型融合的方法来输出结果,最终的效果很好;
修改特征和模型参数
- 可以通过添加或者修改特征,提高模型的上限.
- 通过修改模型的超参数,使模型逼近上限
3.数据探索 (Exploratory Data Analysis)
先看看数据包含哪些东西,在 Data 页签下载 train.csv 和 test.csv 两个文件,分别存着官方给的训练和测试数据,这其中既有离散型也有连续性特征,而且存在大量的缺失值,但是官方提供了 data_description.txt 这个文件,里面对各个特征的含义进行了描述,理解了其中内容后对于大部分缺失值就进行填充了。
pandas 是常用的 python 数据处理包,把 csv 文件读入成 dataframe 格式(可以想象成excel),具体数据展示在上图的 ipython notebook中。
我们看到,总共有81个属性,其中 " SalePrice " 字段表示的是该房子的售价,其余都是房子的相关信息,每一列的属性含义如下(参考data_description.txt):
我们让 dataframe 展示一些信息,如下所示:

数据有分布,有不同的业务意义,我们可以通过matplotlib 、seaborn 画图更加深入理解某些属性的意义,然后构造或是提取出有用的特征。
3.1 数据可视化分析
每条数据都这么多属性,那我们如何知道哪些属性更有用,而又应该怎么用它们?
仅仅最上面的对数据了解,依旧无法给我们提供想法和思路,我们再深入一点来看看我们的数据,看看每个/多个 属性和最后的 " SalePrice " 之间有着什么样的关系呢?
脑容量太有限了,看数据实在不很难分析出来,我们还是画些图来看看属性和房屋售价之间的关系:
- 分析“SalePrice” :


使用seaborn 进行可视化展示,matplotlib作的直方图最大的区别在于有一条密度曲线,通过图形可以看出房价呈现正态分布。
- 相关性分析
相关度特征排序,寻找10个最相关的特征信息。
相关性协方差表 corr()函数,返回结果接近 0 说明无相关性,大于 0 说明是正相关,小于 0是负相关,如果两个变量相互独立,他们的协方差(covariance)为 0 。
我们可以看出跟房产售价最相关的10个数值属性为:
‘OverallQual’ : 整体材料和装修评分
‘GrLivArea’ : 地上面积
‘GarageCars’ : 车库容量
‘GarageArea’ : 车库面积
‘TotalBsmtSF’ :地下室面积
‘1stFlrSF’ : 一楼的平方英尺
‘FullBath’ :完整浴室
‘TotRmsAbvGrd’:地上总房间数
‘YearBuilt’ : 建造年份
此外,通过分析数据的特殊属性,还有以下非数值属性需要纳入考虑范围:
‘Neighborhood’ :表示房屋所处市区的位置
‘CentralAir’ :是否有中央空调
…
上图的关系矩阵只是数值型的,像Neighborhood这种离散型数据则没有参与计算,所以下面尝试着使用sklearn来对这些特征进行处理。
由上图可以看到’CentralAir’, 'Neighborhood’这两个特征对房价的影响并不大,所以后面将不予考虑。
- GrLivArea 地上面积 和 SalePrice的关系:
一般认为房子面积越大,售价越高,从图上看大致也是这个趋势。
此外,从上图knack有两个离群的 GrLivArea 值很高的数据,我们可以猜测下其原因,或许他们代表了贫困地区,也就解释了低价。 这两个点很明显不能代表典型样例,所以我们将它们定义为异常值并删除。
-
中央空调和 SalePrice 的关系(类别型特征)
可以很明显的看到有中央空调的房价明显比较高。 -
OverallQual 整体材料和装修评价
可以很明显的看到OverallQual 评价越好的房价明显比较高。
3.2 数据清洗
这里主要是处理缺失值,首先来看各特征的缺失值数量:
我们已经进行了数据清洗,并且发现了 SalePrice 的很多信息,现在我们要更进一步理解 SalePrice 。


接下来对 GrLivArea、OverallQual等进行画图分析,然后都进行数据装换。
4.模型选择
4.1 数据标准化
4.2 开始建模
可选单个模型模型,比如线性回归(Ridge、Lasso)、树回归、GBDT、XGBoost、LightGBM 等。
import xgboost as xgb
import lightgbm as lgb
from sklearn.linear_model import ElasticNet, Lasso, BayesianRidge, LassoLarsIC
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.kernel_ridge import KernelRidge
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import RobustScaler
from sklearn.base import BaseEstimator, TransformerMixin, RegressorMixin, clone
from sklearn.model_selection import KFold, cross_val_score, train_test_split
from sklearn.metrics import mean_squared_error
#定义交叉验证函数
n_folds = 5
def rmsle_cv(model):
kf = KFold(n_folds, shuffle=True, random_state=42).get_n_splits(x_train)
# np.sqrt(x)返回x的平方根
# cross_val_score方法:
# 这个方法是对数据进行多次分割,然后训练多个模型并评分,每次分割不一样。之后我们用评分的均值来代表这个模型的得分。
# 方法重要参数是:cv代表计算多少次,分割次数;scoring代表方法。
# 损失函数
rmse= np.sqrt(-cross_val_score(model, x_train, y_train, scoring="neg_mean_squared_error", cv = kf))
return(rmse)
# 模型选择
## LASSO Regression : # Linear least squares with L1 regularization.
lasso = make_pipeline(RobustScaler(), Lasso(alpha=0.0005, random_state=1))
# Elastic Net Regression
ENet = make_pipeline(RobustScaler(), ElasticNet(alpha=0.0005, l1_ratio=.9, random_state=3))
# Kernel Ridge Regression
KRR = KernelRidge(alpha=0.6, kernel='polynomial', degree=2, coef0=2.5)
## Gradient Boosting Regression
GBoost = GradientBoostingRegressor(
n_estimators=3000,
learning_rate=0.05,
max_depth=4,
max_features='sqrt',
min_samples_leaf=15,
min_samples_split=10,
loss='huber',
random_state=5)
## XGboost
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)
## lightGBM
model_lgb = lgb.LGBMRegressor(
objective='regression',
num_leaves=5,
learning_rate=0.05,
n_estimators=720,
max_bin=55,
bagging_fraction=0.8,
bagging_freq=5,
feature_fraction=0.2319,
feature_fraction_seed=9,
bagging_seed=9,
min_data_in_leaf=6,
min_sum_hessian_in_leaf=11)
## 对这些基本模型进行打分
score = rmsle_cv(lasso)
print("\nLasso score: {:.4f} ({:.4f})\n".format(score.mean(), score.std()))
score = rmsle_cv(ENet)
print("ElasticNet score: {:.4f} ({:.4f})\n".format(score.mean(), score.std()))
score = rmsle_cv(KRR)
print(
"Kernel Ridge score: {:.4f} ({:.4f})\n".format(score.mean(), score.std()))
score = rmsle_cv(GBoost)
print("Gradient Boosting score: {:.4f} ({:.4f})\n".format(score.mean(),
score.std()))
score = rmsle_cv(model_xgb)
print("Xgboost score: {:.4f} ({:.4f})\n".format(score.mean(), score.std()))
score = rmsle_cv(model_lgb)
print("LGBM score: {:.4f} ({:.4f})\n".format(score.mean(), score.std()))
也可以将多个模型组合起来,进行模型融合。比如Averaging、stacking等方法,好的特征决定模型上限,好的模型和参数可以无线逼近上限。
在机器学习中,集成方法(ensemble learning)把许多个体预测器(base estimator)组合起来,从而提高整体模型的鲁棒性和泛化能力。
集成方法有两大类:
Averaging:独立建造多个个体模型,再取它们各自预测值的平均,作为集成模型的最终预测;能够降低variance。例子:随机森林、bagging。
Boosting:顺序建立一系列弱模型,每一个弱模型都努力降低bias,从而得到一个强模型,最终的预测结果,是所有预测器的加权平均(或投票结果)。例子:AdaBoost、Gradient Boosting、XGBoost、LightGBM。
# 这里使用Boosting模型融合:
class AveragingModels(BaseEstimator, RegressorMixin, TransformerMixin):
def __init__(self, models):
self.models = models
# we define clones of the original models to fit the data in
def fit(self, X, y):
self.models_ = [clone(x) for x in self.models]
# Train cloned base models
for model in self.models_:
model.fit(X, y)
return self
# Now we do the predictions for cloned models and average them
def predict(self, X):
predictions = np.column_stack(
[model.predict(X) for model in self.models_])
return np.mean(predictions, axis=1)
# 评价这四个模型的好坏
stacked_averaged_models = AveragingModels(models=(ENet, GBoost, KRR, lasso))
score = rmsle_cv(stacked_averaged_models)
print(" Averaged base models score: {:.4f} ({:.4f})\n".format(score.mean(),
score.std()))
5.预测结果
from sklearn.metrics import mean_squared_log_error
# 最终对模型的训练和预测
def rmsle(y_train,y_pre):
return np.sqrt(mean_squared_error(y_train, y_pre))
# StackedRegressor
stacked_averaged_models.fit(x_train, y_train)
stacked_train_pred = stacked_averaged_models.predict(x_train)
stacked_pred = np.expm1(stacked_averaged_models.predict(x_test))
# Root Mean Squared Logarithmic Error
print(np.sqrt(mean_squared_error(y_train, stacked_train_pred)))
# XGBoost
model_xgb.fit(x_train, y_train)
xgb_train_pred = model_xgb.predict(x_train)
xgb_pred = np.expm1(model_xgb.predict(x_test))
print(rmsle(y_train, xgb_train_pred))
# lightGBM
model_lgb.fit(x_train, y_train)
lgb_train_pred = model_lgb.predict(x_train)
lgb_pred = np.expm1(model_lgb.predict(x_test))
print(rmsle(y_train, lgb_train_pred))
'''RMSE on the entire Train data when averaging'''
print('RMSLE score on train data:')
#结果是所有预测器的加权平均
print(rmsle(y_train, stacked_train_pred * 0.70 + xgb_train_pred * 0.15 +lgb_train_pred * 0.15))
把结果提交到kaggle上,得分0.15755:
初步的排名不是很好(但是相差不大),看来还得继续优化!!
6.总结
对于任何的机器学习问题,不要一上来就追求尽善尽美,先用自己会的基本算法撸一个 baseline 的 model 出来,再进行后续的分析步骤,一步步提高。
本文 kernel 地址:
https://www.kaggle.com/lomodays/kernela25bad0b84/notebook?scriptVersionId=9988077
几点 Tricks 跟大家共勉:
特征工程(feature engineering) 为王!
很有必要搭建一个 Pipeline,至少要能够自动训练并记录最佳参数!
要做模型融合(model ensemble)!
