[实践]房价预测

数据来源:房价预测数据

数据预处理

检视源数据集

导入numpy库与pandas库,读取源数据,可以先通过head()观察前几行数据。

import numpy as np
import pandas as pd
train_df = pd.read_csv('../input/train.csv', index_col=0)
test_df = pd.read_csv('../input/test.csv', index_col=0)

观察目标值,SalePrice,即我们需要预测的值,如图

%matplotlib inline
#使用%matplotlib命令可以将matplotlib的图表直接嵌入到Notebook之中,或者使用指定的界面库显示图表,
#它有一个参数指定matplotlib图表的显示方式。inline表示将图表嵌入到Notebook中。
price = pd.DataFrame({"price":train_df["SalePrice"]})
price.hist()

这里写图片描述

发现label本身并不平滑。为了我们分类器的学习更加准确,我们会首先把label给“平滑化”(正态化),我们使用log1p, 也就是 log(x+1) 。处理后的label值如下,分布很平均,对于训练集的label便做这样的平滑:

# price = pd.DataFrame({"log(price + 1)":np.log1p(train_df["SalePrice"])})
# price.hist()

这里写图片描述

y_train = np.log1p(train_df.pop('SalePrice'))

先取出训练集的标签,然后将训练集与测试集的数据以列对齐的形式合并,统一做变量转化,我们发现数据为(2919, 79),表示有2919个样本和79个变量

y_train = np.log1p(train_df.pop('SalePrice'))
all_df = pd.concat((train_df, test_df), axis=0)
all_df.shape

特征工程

类别值数据处理

观察数据发现MSSubClass 的值是以数字的方式表示类别(category),
但Pandas在使用数据框的时候,这类数字符号会被默认记成数字,所以这个变量需要转化成string,可以通过value_counts()查看各个类别的样本个数

all_df['MSSubClass'] = all_df['MSSubClass'].astype(str)

对category数据,通常用One-Hot的方法来,pandas自带的get_dummies方法,可以做到One-Hot。One-Hot:是指把数据的各个属性转换为一个向量表示,向量上的每个维度就表示了一个特征属性,同一时间只有一个激活点(1表示激活,其余维度为0),这样对数据做了升维处理,数据也变得更加稀疏,处理后的数据为(2919,303),从79个特征升级到303个特征。

all_dummy_df = pd.get_dummies(all_df)

连续值数值处理

numerical的变量数据可能出现缺失的问题

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

LotFrontage 486
GarageYrBlt 159
MasVnrArea 23
BsmtHalfBath 2
BsmtFullBath 2
BsmtFinSF2 1
GarageCars 1
TotalBsmtSF 1
BsmtUnfSF 1
GarageArea 1
dtype: int64

可以看到,缺失最多的column是LotFrontage
在这里,我们用平均值来填满这些空缺。

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

处理后的缺失值为0。

一般来说,regression的分类器都比较傲娇,最好是把源数据给放在一个标准分布内。不要让数据间的差距太大。所以下一步,标准化numerical数据,这里我们利用 XXs 让数据点更平滑,更便于计算,同样也可以继续使用前面的平滑化方法。

numeric_cols = all_df.columns[all_df.dtypes != 'object']
# 获取numerical变量
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

建模

把数据集分回 训练/测试集

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

岭回归

岭回归,Ridge Regression,是加入L2正则的最小二乘,Sklearn库提供了函数Ridge(alpha),alpha是超参数,是正则化项的系数,用来弱化变量参数共线性,限制变量权重(参数)过大,alpha越大,越不容易过拟合。

导入岭回归相关库,把DataFrame转化成Numpy Array,用Sklearn自带的cross validation方法来测试模型,选用负均方误差(neg_mean_squared_error)作为score,得分是负数,这里的neg_mean_squared_error是一种奖励函数,优化的目标的使其最大化,而分类错误率是一种损失函数,优化的目标是使其最小化,所以取得分的相反数再开方,即均方根误差。获取最优参数,通过绘图发现,大概alpha=10~20的时候,可以把score达到0.135左右。

from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt

X_train = dummy_train_df.values
X_test = dummy_test_df.values

alphas = np.logspace(-3, 2, 50)
#生成从-3到2的50个元素的以10为底的对数等分向量
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))

%matplotlib inline
plt.plot(alphas, test_scores)
plt.title("Alpha vs CV Error");

这里写图片描述

随机森林

利用RandomForestRegressor预测房价。
RandomForestRegressor的参数主要是 n_estimators 和 max_features。 前者(n_estimators)是森林里树的数量,通常数量越大,效果越好,但是计算时间也会随之增加。 当树的数量超过一个临界值之后,算法的效果并不会很显著地变好。 后者(max_features)是根据节点划分的特征的最大值。 这个值越低,方差减小得越多,但是偏差的增大也越多。 根据经验,回归问题中使用 max_features = n_features, 分类问题使用 max_features = n_features (其中 n_features 是特征的个数)是比较好的默认值,这里的小数表示占比该节点下所有特征。 max_depth = None 和 min_samples_split = 2 结合通常会有不错的效果(即生成完全的树)。 但这些(默认)值通常不是最佳的,同时还可能消耗大量的内存,最佳参数值应由交叉验证获得。 另外,在随机森林中,默认使用自助采样法(bootstrap = True)(有放回重复采样)。用RF最优值可以达到0.137.

from sklearn.ensemble import RandomForestRegressor

max_features = [.1, .3, .5, .7, .9, .99]
test_scores = []
for max_feat in max_features:
    clf = RandomForestRegressor(n_estimators=200, max_features=max_feat)
    test_score = np.sqrt(-cross_val_score(clf, X_train, y_train, cv=5, scoring='neg_mean_squared_error'))
    test_scores.append(np.mean(test_score))

plt.plot(max_features, test_scores)
plt.title("Max Features vs CV Error");

这里写图片描述

Ensemble

stacking

stacking是一种组合多个模型的方法,常用来组合不同类型的模型。
这里以Stacking的思维来汲取两种或者多种模型的优点
提取最优parameter,做成最终的model,将各模型得到的预测值作为新的input,再做一次预测,这里直接使用『平均化』。前面有对label做过平滑处理,此处需要还原。

ridge = Ridge(alpha=15)
rf = RandomForestRegressor(n_estimators=500, max_features=.3)

ridge.fit(X_train, y_train)
rf.fit(X_train, y_train)

y_ridge = np.expm1(ridge.predict(X_test))
y_rf = np.expm1(rf.predict(X_test))

y_final = (y_ridge + y_rf) / 2
submission_df = pd.DataFrame(data= {'Id' : test_df.index, 'SalePrice': y_final})

bagging

Bagging的训练集选择是随机的,均匀采样,各轮训练集之间相互独立,基础学习器没有权重,并行生成,最后的预测对分类问题一般采用投票方式,对回归问题采用简单平均方法。
BaggingRegressor的主要参数有n_estimators,表示基础分类器个数, base_estimator表示基础分类器模型,默认是决策树DecisionTree,这里选用Ridge(15),最后的分类错误率可以低于0.132。

from sklearn.linear_model import Ridge
ridge = Ridge(15)

from sklearn.ensemble import BaggingRegressor

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

这里写图片描述

boosting

Boostlng的训练集的选择是独立的,根据错误率采样,各轮训练集的选择与前轮的学习结果有关,基础学习器是串行生成。同Bagging,它也是揽来一把的分类器,不过需要线性排列,下一个分类器把上一个分类器分类得不好的地方加上更高的权重,这样下一个分类器就能在这个部分学得更加“深刻”。对正确分类的样本降权,对错误分类的样本加权(而这些样本通常就是分类边界附近的样本),最后分类器是多个弱分类器的加权组合(线性叠加),通过提升弱分类器的分类精度提升学习器的性能。

这里boosting选用AdaBoostRegressor时,用法同BaggingRegressor,Adaboost+Ridge在这里,25个小分类器的情况下,可以达到了接近0.132的效果。也可以尝试默认的学习器(决策树)训练,不过效果不是很好。

from sklearn.ensemble import AdaBoostRegressor

params = [10, 15, 20, 25, 30, 35, 40, 45, 50]
test_scores = []
for param in params:
    clf = AdaBoostRegressor(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");

这里写图片描述

最后尝试一下XGBoost,这是在Kaggle运用效果最好的一款Boosting框架的模型,结果显示,树的深度为5的时候,错误率可以缩小到0.127。

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");

这里写图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值