每日一课kaggle练习讲解House-Prices

每日一课 Kaggle 练习讲解

每天一道Kaggle题,学习机器学习!

今天给大家来讲讲《House Prices: Advanced Regression Techniques》(房价预测模型)的思路:

  • (1) 数据可视化和数据分布变换
  • (2) 缺省值处理
  • (3) 数据特征变换
  • (4) 数据建模及交叉检验
  • (5) 模型组合
In [1]:
import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
from scipy.stats import norm, skew
from scipy.special import boxcox1p
from scipy.stats import boxcox_normmax
from sklearn.model_selection import KFold, cross_val_score
from sklearn.preprocessing import LabelEncoder
%matplotlib inline

加载数据

去除ID

In [2]:
train_path = "http://kaggle.shikanon.com/house-prices-advanced-regression-techniques/train.csv"
test_path = "http://kaggle.shikanon.com/house-prices-advanced-regression-techniques/test.csv"
train_df = pd.read_csv(train_path)
test_df = pd.read_csv(test_path)
train_df.head()
Out[2]:
Id MSSubClass MSZoning LotFrontage LotArea Street Alley LotShape LandContour Utilities ... PoolArea PoolQC Fence MiscFeature MiscVal MoSold YrSold SaleType SaleCondition SalePrice
0 1 60 RL 65.0 8450 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 2 2008 WD Normal 208500
1 2 20 RL 80.0 9600 Pave NaN Reg Lvl AllPub ... 0 NaN NaN NaN 0 5 2007 WD Normal 181500
2 3 60 RL 68.0 11250 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 9 2008 WD Normal 223500
3 4 70 RL 60.0 9550 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 2 2006 WD Abnorml 140000
4 5 60 RL 84.0 14260 Pave NaN IR1 Lvl AllPub ... 0 NaN NaN NaN 0 12 2008 WD Normal 250000

5 rows × 81 columns

我们在分析之前要先了解个字段的意思:

In [3]:
train_df.columns
Out[3]:
Index(['Id', 'MSSubClass', 'MSZoning', 'LotFrontage', 'LotArea', 'Street',
       'Alley', 'LotShape', 'LandContour', 'Utilities', 'LotConfig',
       'LandSlope', 'Neighborhood', 'Condition1', 'Condition2', 'BldgType',
       'HouseStyle', 'OverallQual', 'OverallCond', 'YearBuilt', 'YearRemodAdd',
       'RoofStyle', 'RoofMatl', 'Exterior1st', 'Exterior2nd', 'MasVnrType',
       'MasVnrArea', 'ExterQual', 'ExterCond', 'Foundation', 'BsmtQual',
       'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinSF1',
       'BsmtFinType2', 'BsmtFinSF2', 'BsmtUnfSF', 'TotalBsmtSF', 'Heating',
       'HeatingQC', 'CentralAir', 'Electrical', '1stFlrSF', '2ndFlrSF',
       'LowQualFinSF', 'GrLivArea', 'BsmtFullBath', 'BsmtHalfBath', 'FullBath',
       'HalfBath', 'BedroomAbvGr', 'KitchenAbvGr', 'KitchenQual',
       'TotRmsAbvGrd', 'Functional', 'Fireplaces', 'FireplaceQu', 'GarageType',
       'GarageYrBlt', 'GarageFinish', 'GarageCars', 'GarageArea', 'GarageQual',
       'GarageCond', 'PavedDrive', 'WoodDeckSF', 'OpenPorchSF',
       'EnclosedPorch', '3SsnPorch', 'ScreenPorch', 'PoolArea', 'PoolQC',
       'Fence', 'MiscFeature', 'MiscVal', 'MoSold', 'YrSold', 'SaleType',
       'SaleCondition', 'SalePrice'],
      dtype='object')
  • MSSubClass: 建筑的等级,类型:类别型
  • MSZoning: 区域分类,类型:类别型
  • LotFrontage: 距离街道的直线距离,类型:数值型,单位:英尺
  • LotArea: 地皮面积,类型:数值型,单位:平方英尺
  • Street: 街道类型,类型:类别型
  • Alley: 巷子类型,类型:类别型
  • LotShape: 房子整体形状,类型:类别型
  • LandContour: 平整度级别,类型:类别型
  • Utilities: 公共设施类型,类型:类别型
  • LotConfig: 房屋配置,类型:类别型
  • LandSlope: 倾斜度,类型:类别型
  • Neighborhood: 市区物理位置,类型:类别型
  • Condition1: 主干道或者铁路便利程度,类型:类别型
  • Condition2: 主干道或者铁路便利程度,类型:类别型
  • BldgType: 住宅类型,类型:类别型
  • HouseStyle: 住宅风格,类型:类别型
  • OverallQual: 整体材料和饰面质量,类型:数值型
  • OverallCond: 总体状况评价,类型:数值型
  • YearBuilt: 建筑年份,类型:数值型
  • YearRemodAdd: 改建年份,类型:数值型
  • RoofStyle: 屋顶类型,类型:类别型
  • RoofMatl: 屋顶材料,类型:类别型
  • Exterior1st: 住宅外墙,类型:类别型
  • Exterior2nd: 住宅外墙,类型:类别型
  • MasVnrType: 砌体饰面类型,类型:类别型
  • MasVnrArea: 砌体饰面面积,类型:数值型,单位:平方英尺
  • ExterQual: 外部材料质量,类型:类别型
  • ExterCond: 外部材料的现状,类型:类别型
  • Foundation: 地基类型,类型:类别型
  • BsmtQual: 地下室高度,类型:类别型
  • BsmtCond: 地下室概况,类型:类别型
  • BsmtExposure: 花园地下室墙,类型:类别型
  • BsmtFinType1: 地下室装饰质量,类型:类别型
  • BsmtFinSF1: 地下室装饰面积,类型:类别型
  • BsmtFinType2: 地下室装饰质量,类型:类别型
  • BsmtFinSF2: 地下室装饰面积,类型:类别型
  • BsmtUnfSF: 未装饰的地下室面积,类型:数值型,单位:平方英尺
  • TotalBsmtSF: 地下室总面积,类型:数值型,单位:平方英尺
  • Heating: 供暖类型,类型:类别型
  • HeatingQC: 供暖质量和条件,类型:类别型
  • CentralAir: 中央空调状况,类型:类别型
  • Electrical: 电力系统,类型:类别型
  • 1stFlrSF: 首层面积,类型:数值型,单位:平方英尺
  • 2ndFlrSF: 二层面积,类型:数值型,单位:平方英尺
  • LowQualFinSF: 低质装饰面积,类型:数值型,单位:平方英尺
  • GrLivArea: 地面以上居住面积,类型:数值型,单位:平方英尺
  • BsmtFullBath: 地下室全浴室,类型:数值
  • BsmtHalfBath: 地下室半浴室,类型:数值
  • FullBath: 高档全浴室,类型:数值
  • HalfBath: 高档半浴室,类型:数值
  • BedroomAbvGr: 地下室以上的卧室数量,类型:数值
  • KitchenAbvGr: 厨房数量,类型:数值
  • KitchenQual: 厨房质量,类型:类别型
  • TotRmsAbvGrd: 地上除卧室以外的房间数,类型:数值
  • Functional: 房屋功用性评级,类型:类别型
  • Fireplaces: 壁炉数量,类型:数值
  • FireplaceQu: 壁炉质量,类型:类别型
  • GarageType: 车库位置,类型:类别型
  • GarageYrBlt: 车库建造年份,类别:数值型
  • GarageFinish: 车库内饰,类型:类别型
  • GarageCars: 车库车容量大小,类别:数值型
  • GarageArea: 车库面积,类别:数值型,单位:平方英尺
  • GarageQual: 车库质量,类型:类别型
  • GarageCond: 车库条件,类型:类别型
  • PavedDrive: 铺的车道情况,类型:类别型
  • WoodDeckSF: 木地板面积,类型:数值型,单位:平方英尺
  • OpenPorchSF: 开放式门廊区面积,类型:数值型,单位:平方英尺
  • EnclosedPorch: 封闭式门廊区面积,类型:数值型,单位:平方英尺
  • 3SsnPorch: 三个季节门廊面积,类型:数值型,单位:平方英尺
  • ScreenPorch: 纱门门廊面积,类型:数值型,单位:平方英尺
  • PoolArea: 泳池面积,类型:数值型,单位:平方英尺
  • PoolQC:泳池质量,类型:类别型
  • Fence: 围墙质量,类型:类别型
  • MiscFeature: 其他特征,类型:类别型
  • MiscVal: 其他杂项特征值,类型:类别型
  • MoSold: 卖出月份,类别:数值型
  • YrSold: 卖出年份,类别:数值型
  • SaleType: 交易类型,类型:类别型
  • SaleCondition: 交易条件,类型:类别型

数据处理和特征分析

In [4]:
#Saving Ids
train_ID = train_df['Id']
test_ID = test_df['Id']

#Dropping Ids
train_df.drop("Id", axis = 1, inplace = True)
test_df.drop("Id", axis = 1, inplace = True)

数据观察和可视化

更加常识,一般和房价最相关的是居住面积,也就是GrLivArea,我们查看下GrLivAreaSalePrice的关系

In [5]:
fig, ax = plt.subplots()
ax.scatter(x = train_df['GrLivArea'], y = train_df['SalePrice'], c = "skyblue")
plt.ylabel('SalePrice', fontsize=8)
plt.xlabel('GrLivArea', fontsize=8)
plt.show()

我们发现有个别值特别的偏离,GrLivArea有两个点在4000以上,但其价格不到200000,首先这种点特别少(不到总数的3%),我们把他作为异常值去掉(其实是否去掉我们可以多做几次实验来验证)

Kaggle的作者在这里有建议去掉:)

In [6]:
train_df.drop(train_df[(train_df['GrLivArea']>4000)&(train_df['GrLivArea']<30000)].index,inplace=True)
In [7]:
fig, ax = plt.subplots()
ax.scatter(x = train_df['GrLivArea'], y = train_df['SalePrice'], c = "skyblue")
plt.ylabel('SalePrice', fontsize=8)
plt.xlabel('GrLivArea', fontsize=8)
plt.show()
  • 最后一行是 SalePrice, 我们可以看到她跟各变量的关系,还有各变量相互之间的关系

观察数据分布

在机器学习中,对数据的认识是很重要的,他会影响我们的特征构建和建模,特别对于偏态分布,我们要做一些变换

In [8]:
# 统计表述
train_df['SalePrice'].describe()
Out[8]:
count      1456.000000
mean     180151.233516
std       76696.592530
min       34900.000000
25%      129900.000000
50%      163000.000000
75%      214000.000000
max      625000.000000
Name: SalePrice, dtype: float64
In [9]:
# 绘制分布图
sns.distplot(train_df['SalePrice'], 
             kde_kws={"color": "coral", "lw": 1, "label": "KDE"}, 
             hist_kws={"histtype": "stepfilled", "linewidth": 3, "alpha": 1, "color": "skyblue"});

Q-Q图,全称 Quantile Quantile Plot,中文名叫分位数图,Q-Q图是一个概率图,用于比较观测与预测值之间的概率分布差异,这里的比较对象一般采用正态分布,Q-Q图可以用于检验数据分布的相似性,而P-P图是根据变量的累积概率对应于所指定的理论分布累积概率绘制的散点图,两者基本一样

In [10]:
# 绘制P-P图
fig = plt.figure()
res = stats.probplot(train_df['SalePrice'], dist="norm", plot=plt)
plt.show()

红色线是正态分布,蓝色线是我们的数据,可以看出,我们的数据头尾都严重偏离了正太分布,我们尝试对数据做变换,常用的变换有指数变换、对数变换、幂函数等。

In [11]:
# 对数变换

train_df['SalePrice_Log'] = np.log(train_df['SalePrice'])

sns.distplot(train_df['SalePrice_Log'], 
             kde_kws={"color": "coral", "lw": 1, "label": "KDE"}, 
             hist_kws={"histtype": "stepfilled", "linewidth": 3, "alpha": 1, "color": "skyblue"});
 
# 偏度与峰值(skewness and kurtosis)
print("Skewness: %f" % train_df['SalePrice_Log'].skew())
print("Kurtosis: %f" % train_df['SalePrice_Log'].kurt())

fig = plt.figure()
res = stats.probplot(train_df['SalePrice_Log'], plot=plt)
plt.show()
Skewness: 0.065449
Kurtosis: 0.666438
In [12]:
# 指数变换
train_df['SalePrice_Exp'] = np.exp(train_df['SalePrice']/train_df['SalePrice'].mean())

sns.distplot(train_df['SalePrice_Exp'], 
             kde_kws={"color": "coral", "lw": 1, "label": "KDE"}, 
             hist_kws={"histtype": "stepfilled", "linewidth": 3, "alpha": 1, "color": "skyblue"});
 
# 偏度与峰值(skewness and kurtosis)
print("Skewness: %f" % train_df['SalePrice_Exp'].skew())
print("Kurtosis: %f" % train_df['SalePrice_Exp'].kurt())

fig = plt.figure()
res = stats.probplot(train_df['SalePrice_Exp'], plot=plt)
plt.show()
Skewness: 6.060076
Kurtosis: 56.822460
In [13]:
# 幂函数变换
train_df['SalePrice_Square'] = train_df['SalePrice']**0.5

sns.distplot(train_df['SalePrice_Square'], 
             kde_kws={"color": "coral", "lw": 1, "label": "KDE"}, 
             hist_kws={"histtype": "stepfilled", "linewidth": 3, "alpha": 1, "color": "skyblue"});
 
# 偏度与峰值(skewness and kurtosis)
print("Skewness: %f" % train_df['SalePrice_Square'].skew())
print("Kurtosis: %f" % train_df['SalePrice_Square'].kurt())

fig = plt.figure()
res = stats.probplot(train_df['SalePrice_Square'], plot=plt)
plt.show()
Skewness: 0.810797
Kurtosis: 1.245798