第一步:导入基本的模块, 并且加载数据。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# index_col=0  将第0列作为行索引
train_df = pd.read_csv('data/home_price/train.csv', index_col=0)
test_df = pd.read_csv('data/home_price/test.csv', index_col=0)
# print(train_df.head())
# print(train_df.shape)

   下面是读取出来的数据       数据集下载地址:https://www.kaggle.com/c/house-prices-advanced-regression-techniques

MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities LotConfig ... PoolArea PoolQC Fence MiscFeature MiscVal MoSold YrSold SaleType SaleCondition SalePrice
Id                                          
1 60 RL 65.0 8450 Pave NaN Reg Lvl AllPub Inside ... 0 NaN NaN NaN 0 2 2008 WD Normal 208500
2 20 RL 80.0 9600 Pave NaN Reg Lvl AllPub FR2 ... 0 NaN NaN NaN 0 5 2007 WD Normal 181500
3 60 RL 68.0 11250 Pave NaN IR1 Lvl AllPub Inside ... 0 NaN NaN NaN 0 9 2008 WD Normal 223500
4 70 RL 60.0 9550 Pave NaN IR1 Lvl AllPub Corner ... 0 NaN NaN NaN 0 2 2006 WD Abnorml 140000
5 60 RL 84.0 14260 Pave NaN IR1 Lvl AllPub FR2 ... 0 NaN NaN NaN 0 12 2008 WD Normal 250000

 5 rows × 80 columns

      kaggle平台提供了两张表,一张是带标签的数据(训练数据), 一张是不带标签的数据(测试数据)。接下来,我想做的就是将带有标签数据的标签列删除,它也就变成不带标签的数据。在将测试数据与其进行合并。这么做主要是为了统一进行数据预处理的时候更加方便。等所有的需要的预处理进行完之后,我们再把他们分隔开。

第二步:合并数据

prices = pd.DataFrame({'price': train_df['SalePrice'], 'log(price+1)': np.log1p(train_df['SalePrice'])})
prices.hist()   # 画图 看一下标签是否平滑
plt.show()

y_train = np.log1p(train_df.pop('SalePrice'))  # 将原来的标签删除 剩下log(price+1)列的数据
all_df = pd.concat((train_df, test_df), axis=0) # 将train_df, test_df合并

     我们这里除了将标签取下来,还构造了一个新列log(price+1) 这样主要是为了不让数据倾斜。  也就是让数据尽可能服从高斯分布。log1p(x) 就是log(x+1)。  这里我们将数据进行了平滑,那么按“怎么来的怎么去”原则,最后的预测结果就需要expm1()。 也就是将预测结果变为真实的房价数。   log1p反运算就是expm1()

第三步:特征工程(处理缺失值等)

# 有些数据的取值只有四五,或者可数个。这类数据我们转为one_hot编码

# 发现MSSubClass值应该是分类值
print(all_df['MSSubClass'].dtypes)  # int64
all_df['MSSubClass'] = all_df['MSSubClass'].astype(str)
print(all_df['MSSubClass'].value_counts())
# 我们将category的变量转变为numerical表达形式
# 当我们用numerical来表达categorical的时候,要注意,数字本身有大小。
# 不能乱指定大小,我们采用one_hot编码
# pandas自带的get_dummies方法可以一键做到one_hot
print(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)


# 缺失值处理

# 统计每列缺失值情况
print(all_dummy_df.isnull().sum().sort_values(ascending=False).head())
# 可以看到,缺失最多的column是LotFrontage
# 处理这些缺失的信息,得靠好好审题。一般来说,数据集的描述里会写的很清楚,这些缺失都代表着什么。当然,如果实在没有的话,也只能靠自己的『想当然』。。
# 在这里,我们用平均值来填满这些空缺

# 我们用均值填充
mean_cols = all_dummy_df.mean()
all_dummy_df = all_dummy_df.fillna(mean_cols)

# 再检查一下是否有缺失值
print(all_dummy_df.isnull().sum().sum())


# 标准化数字型数据

# 标准化numerical数据¶
# 这一步并不是必要,但是得看你想要用的分类器是什么。一般来说,regression的分类器都比较傲娇,最好是把源数据给放在一个标准分布内。不要让数据间的差距太大。
# 这里,我们当然不需要把One-Hot的那些0/1数据给标准化。我们的目标应该是那些本来就是numerical的数据:

# 先找出数字型数据
numeric_cols = all_df.columns[all_df.dtypes != 'object']
# print(numeric_cols)
# 对其标准化
numeric_col_mean = 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_mean) / numeric_col_std

# 将合并的数据此时进行拆分  分为训练数据和测试数据
dummy_train_df = all_dummy_df.loc[train_df.index]
dummy_test_df = all_dummy_df.loc[test_df.index]
   这一步我们分别进行了:将训练数据和测试数据进行合并,主要是为了方便进行统一处理; 将category型的数据转化为one_hot编码; 对缺失值进行填充; 标准化数据; 将合并的数据又分开。

第四步:模型的建立,预测

  模型1:岭回归

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

X_train = dummy_train_df.values
X_test = dummy_test_df.values

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

# 看那个alpha下 模型预测的更好
plt.plot(alphas, test_scores)
plt.title('Alpha vs CV Error')
plt.show()

  

        根据图像发现alpha值为15左右的时候,模型最佳。 均方误差值为:0.135左右

模型二:随机森林(基本模型我们设为岭回归。一般默认为回归树)

from sklearn.ensemble import RandomForestRegressor

max_features = [0.1, 0.3, 0.5, 0.7, 0.9, 0.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')
plt.show()

        max_features 代表的划分是考虑的最大特征数,可以是大于1的具体数字, 代表考虑多少个特征。 如果是小于1的数字,代表的是特征的百分之多少。

     从上图中我们可以看到当max_feature为0.3左右的时候,均方误差最小。大概也是0.135

模型三:Stacking集成 (用stacking的思维来汲取两种或多种模型的优点)

# 我们用一个Stacking的思维来汲取两种或多种模型的优点
ridge = Ridge(alpha=15)
rf = RandomForestRegressor(n_estimators=500, max_features=0.3)

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

# 上面提到了,因为最前面我们给label做了个log(1+x), 于是这里我们需要把predit的值给exp回去,并且减掉那个"1"
# 所以就是我们的expm1()函数。

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})
# print(submission_df)

   submission_df 就是我们这场比赛需要提交的结果。也就是测试样本的预测值。

模型四: 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')
plt.show()

  bagging就是把多个小分类器放在一起,每个train随机选取一部分,然后把他们的最终结果综合起来(投票制)

     分类器个数为10个的时候  均方误差最小,大概为0.132。 比前面的几种模型好

 模型五:Adaboost

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

 这里的基本分类器依旧是岭回归  ,我们找的还是基分类器个数与均方误差的关系

Adaboos+Ridge, 用35个弱分类器的情况下,均方误差能降到0.141左右。。可以再增加基分类器个数 看图像的走势

模型六:Kaggle神器: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('max_depth vs CV Error')
plt.show()

 

惊了,深度为5的时候,错误率缩小到0.127。。这就是为什么,浮躁的竞赛圈,人人都在用XGBoost