咱们注意到 MSSubClass 实际上是一个 category 的值:算法
all_df['MSSubClass'].dtypes
有:app
dtype('int64')
它不该该作为数值型的值进行统计。所以,进行强制类型转换,把它变回 string:学习
df['MSSubClass'] =df['MSSubClass'].astype(str)
而后,统计其出现频次:测试
all_df['MSSubClass'].value_counts()
就很清楚的了解 MSSubClass 特征了。spa
当咱们用 numerical 来表达 categorical 的时候要注意,数字自己有大小的含义,因此乱用数字会给以后的模型学习带来麻烦。这里咱们能够用 One-Hot 的方法来表达 category。code
pandas 自带的get_dummies
方法,能够作到一键 One-Hot:ip
pd.get_dummies(df['MSSubClass'], prefix='MSSubClass').head()
效果以下:get
此时,MSSubClass 被咱们分红了 12 列,每列表明一个 category,是为 1,否为 0。string
因此,同理。接下来,咱们须要把全部的 category 数据所有一键 One-Hot:pandas
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 的方法有 Bagging 和 Boosting 两大类。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% 左右。整个过程没有对特征信息进行太多的处理,还有太多须要改进的地方。
第一次完完整整的从头至尾本身作了一个比赛,仍是有太多地方浅浅略过,确实,若是只是调参跑模型的话,应该不是难事,可是如何得到更好的效果,数据量大时现有的程序跑不动,须要改进算法等方面,还有太多值得学习的地方,由于这件事好像没有一个最优结果,只有更优的结果。
不足之处,欢迎指正。