房价预测任务
目标:根据房屋属性预测每个房子的最终价格。
任务流程:
(一):分析数据指标
- 不同指标对结果的影响
- 连续值与离散值的情况
(二):观察数据正太性
- 是否满足正太分布
- 数据变换操作
(三):数据预处理
- 缺失值填充
- 标签转换
(四):集成方法建模对比
- 单模型回归效果
- 平均与堆叠效果对比
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy.stats import norm
from sklearn.preprocessing import StandardScaler
from scipy import stats
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
df_train = pd.read_csv('./data/train.csv')
数据指标解释
- MSSubClass:建筑类
- mszoning:一般的分区分类
- LotFrontage:街道连接属性线性英尺
- LotArea:平方英尺批量
- 街道:道路通行方式
- 小巷:通道入口的类型
- LotShape:财产的形状
- LandContour:财产的平整度
- 实用程序:可用的实用程序类型
- LotConfig:很多配置
- LandSlope:坡的财产
- 邻近:Ames市区范围内的物理位置
- 状态:邻近主要道路或铁路
- 条件:靠近主要道路或铁路(如果第二存在)
- BldgType:住宅类型
- housestyle:风格的住宅
- overallqual:整体材料和完成质量
- overallcond:总体状况评价
- yearbuilt:原施工日期
- yearremodadd:重塑日期
- RoofStyle:屋顶类型
- RoofMatl:屋面材料
- exterior1st:外部覆盖的房子
- exterior2nd:外部覆盖的房子(如果有一个以上的材料)
- MasVnrType:砌体饰面型
- masvnrarea:砌体饰面面积平方英尺
- exterqual:外部材料质量
- extercond:在外部的物质条件
- 基金会:基金会的类型
- BsmtQual:地下室的高度
- bsmtcond:地下室的一般条件
- BsmtExposure:罢工或花园层地下室墙
- bsmtfintype1:质量基底成品区
- bsmtfinsf1:型完成1平方英尺
- bsmtfintype2:质量第二成品区(如果有的话)
- bsmtfinsf2:型完成2平方英尺
- BsmtUnfSF:未完成的平方英尺的地下室
- totalbsmtsf:地下室面积总平方英尺
- 加热:加热类型
- heatingqc:加热质量和条件
- 中央:中央空调
- 电气:电气系统
- 1stflrsf:一楼平方英尺
- 2ndflrsf:二楼平方英尺
- lowqualfinsf:完成平方英尺Low质量(各楼层)
- grlivarea:以上等级(地)居住面积平方英尺
- BsmtFullBath: Basement full bathrooms
- BsmtHalfBath:地下室半浴室
- FullBath:完整的浴室级以上
- HalfBath:半浴室级以上
- 卧室:高于地下室的卧室数
- 厨房:厨房数量
- kitchenqual:厨房的品质
- totrmsabvgrd:房间总级以上(不包括卫生间)
- 功能:家庭功能评级
- 一些壁炉壁炉:
- fireplacequ:壁炉质量
- GarageType:车库位置
- GarageYrBlt:建立年车库
- GarageFinish:车库的室内装修
- GarageCars:在汽车车库大小的能力
- GarageArea:在平方英尺的车库规模
- GarageQual:车库质量
- garagecond:车库条件
- paveddrive:铺的车道
- WoodDeckSF:平方英尺的木甲板面积
- openporchsf:平方英尺打开阳台的面积
- enclosedporch:封闭式阳台的面积以平方英尺
- 3ssnporch:平方英尺三季阳台的面积
- screenporch:平方英尺纱窗门廊区
- PoolArea:在平方英尺的游泳池
- poolqc:池质量
- 栅栏:栅栏的质量
- miscfeature:杂项功能在其他类未包括
- miscval:$杂特征值
- MoSold:月销售
- YrSold:年销售
- SaleType:销售类型
- salecondition:销售条件
预测目标分析
df_train['SalePrice'].describe()
count 1460.000000
mean 180921.195890
std 79442.502883
min 34900.000000
25% 129975.000000
50% 163000.000000
75% 214000.000000
max 755000.000000
Name: SalePrice, dtype: float64
sns.distplot(df_train['SalePrice']);
- 偏度和峰度
#skewness and kurtosis
print("Skewness: %f" % df_train['SalePrice'].skew())
print("Kurtosis: %f" % df_train['SalePrice'].kurt())
Skewness: 1.882876
Kurtosis: 6.536282
看起来偏度比较大,我们发现了一条大尾巴,一会咱们把解决掉它。
接下来再看看一些比较重要的属性对结果的影响
#居住面积平方英尺
var = 'GrLivArea'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));
越大的面积,房价肯定也越贵嘛,但是这里出现了一些离群点。
#地下室面积平方英尺
var = 'TotalBsmtSF'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));
离散型变量,我们用boxplot来表示
#整体材料和饰面质量
var = 'OverallQual'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
f, ax = plt.subplots(figsize=(8, 6))
fig = sns.boxplot(x=var, y="SalePrice", data=data)
fig.axis(ymin=0, ymax=800000);
#原施工日期
var = 'YearBuilt'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
f, ax = plt.subplots(figsize=(16, 8))
fig = sns.boxplot(x=var, y="SalePrice", data=data)
fig.axis(ymin=0, ymax=800000);
plt.xticks(rotation=90);
var = 'Neighborhood'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
f, ax = plt.subplots(figsize=(8, 6))
fig = sns.boxplot(x=var, y="SalePrice", data=data)
#fig.axis(ymin=0, ymax=800000);
plt.xticks(rotation=90);
来看看特征之间的相关性吧,看看哪些和价格最相关
#correlation matrix
corrmat = df_train.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, square=True,cmap='YlGnBu');
k = 10 #number of variables for heatmap
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(df_train[cols].values.T)
sns.set(font_scale=1.25)
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10}, yticklabels=cols.values, xticklabels=cols.values,cmap='YlGnBu')
plt.show()
#scatterplot
sns.set()
cols = ['SalePrice', 'OverallQual', 'GrLivArea', 'GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']
sns.pairplot(df_train[cols], size = 2.5)
plt.show();
缺失值的情况
#missing data
total = df_train.isnull().sum().sort_values(ascending=False)
percent = (df_train.isnull().sum()/df_train.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
missing_data.head(20)
import pandas as pd
train = pd.read_csv('./data/train.csv')
test = pd.read_csv('./data/test.csv')
#看看数据多大的
print("The train data size before dropping Id feature is : {} ".format(train.shape))
print("The test data size before dropping Id feature is : {} ".format(test.shape))
#ID先留着,暂时不用
train_ID = train['Id']
test_ID = test['Id']
#去掉ID
train.drop("Id", axis = 1, inplace = True)
test.drop("Id", axis = 1, inplace = True)
#看一下现在的数据的shape
print("\nThe train data size after dropping Id feature is : {} ".format(train.shape))
print("The test data size after dropping Id feature is : {} ".format(test.shape))
The train data size before dropping Id feature is : (1460, 81)
The test data size before dropping Id feature is : (1459, 80)
The train data size after dropping Id feature is : (1460, 80)
The test data size after dropping Id feature is : (1459, 79)
#发现离群点
fig, ax = plt.subplots()
ax.scatter(x = train['GrLivArea'], y = train['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('GrLivArea', fontsize=13)
plt.show()
#干掉离群点
train = train.drop(train[(train['GrLivArea']>4000) & (train['SalePrice']<300000)].index)
#Check the graphic again
fig, ax = plt.subplots()
ax.scatter(train['GrLivArea'], train['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('GrLivArea', fontsize=13)
plt.show()
样本正太分布变换(注:选自张之昊博文)
sns.distplot(train['SalePrice'] , fit=norm);
(mu, sigma) = norm.fit(train['SalePrice'])
print( '\n mu = {:.2f} and sigma = {:.2f}\n'.format(mu, sigma))
#分布图
plt.legend(['Normal dist. ($\mu=$ {:.2f} and $\sigma=$ {:.2f} )'.format(mu, sigma)],
loc='best')
plt.ylabel('Frequency')
plt.title('SalePrice distribution')
#QQ图
fig = plt.figure()
res = stats.probplot(train['SalePrice'], plot=plt)
plt.show()
#对数变换log(1+x)
train["SalePrice"] = np.log1p(train["SalePrice"])
#看看新的分布
sns.distplot(train['SalePrice'] , fit=norm);
# 参数
(mu, sigma) = norm.fit(train['SalePrice'])
print( '\n mu = {:.2f} and sigma = {:.2f}\n'.format(mu, sigma))
#画图
plt.legend(['Normal dist. ($\mu=$ {:.2f} and $\sigma=$ {:.2f} )'.format(mu, sigma)],
loc='best')
plt.ylabel('Frequency')
plt.title('SalePrice distribution')
#QQ图
fig = plt.figure()
res = stats.probplot(train['SalePrice'], plot=plt)
plt.show()
ntrain = train.shape[0]
ntest = test.shape[0]
y_train = train.SalePrice.values
all_data = pd.concat((train, test)).reset_index(drop=True)
all_data.drop(['SalePrice'], axis=1, inplace=True)
print("all_data size is : {}".format(all_data.shape))
all_data size is : (2917, 79)