House Prices: Advanced Regression Techniques

  • 1. 项目描述:

  1. 比赛项目由 Kaggle 举办,要求选手依据爱荷华州房子的质量、面积、街区、壁炉个数等79个变量预测房子的价格。

  2. 预测每个房屋的销售价格是您的工作。对于测试集中的每个ID,您必须预测SalePrice变量的值。

  3. 根据预测值的对数与观察到的销售价格的对数之间的均方根误差(RMSE)评估提交的内容。(记录日志意味着预测昂贵房屋和廉价房屋的错误将同等地影响结果。)

# Kaggle房价预测项目

# 首先,导入需要用到的包
import pandas as pd
import numpy as np

import matplotlib.pyplot as plt
import seaborn as sns
color = sns.color_palette()
sns.set_style('darkgrid')
import warnings
def ignore_warn(*args, **kwargs):
    pass
warnings.warn = ignore_warn

from scipy import stats
from scipy.stats import norm, skew

# 读取数据集
#首先引入Pandas库,然后使用read_csv函数加载当前目录下的数据文件D:/房价预测项目/train.csv,并将数据文件储存为一个DateFrame对象返回
train = pd.read_csv('D:/房价预测项目/train.csv')
test = pd.read_csv('D:/房价预测项目/test.csv')


#print(type(train))
#<class 'pandas.core.frame.DataFrame'>

  • 2. 探索性可视化(Exploratory Visualization)

  • 2.1 对训练集train初步探索
corrmat = train.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, vmax=.8, square=True)
plt.show()
  • 2.2 选出10个与房价相关性最强的变量查看相关性系数
k = 10 #选择变量的个数

# #pandas.nlarge()是输出最大相关排序,排完了之后选取salprice列的索引
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index

#cm返回的相关系数矩阵
cm = np.corrcoef(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)
plt.show()

分析上面的热力图,可以得到如下的结论:

1.‘OverallQual’ ,‘GrLivArea’ , 'TotalBsmtSF’与房价的相关性很强,可以后面再深入探索

2.‘GarageCars’(车库能放多少量车) 和 ‘GarageArea’ (车库面积)和房价同样有比较强的相关性,但这两个变量本身的相关性为0.88,有很强的相关性,车库面积和车库能放多少车本身就是有强相关性的,可能存在多重共线性问题,去除‘GarageCars’,留下‘GarageArea’

3.‘TotalBsmtSF’ 和 ‘1stFloor’ 似乎都是代表地下室面积,这里不确定这两个变量含义的区别,不过它们间的相关性为0.82,也有很强的相关性,考虑去掉一个留下 ‘TotalBsmtSF’

4.通过上面的分析:

大致'OverallQual'(预测房屋质量)与房价应该是强相关,可用可视化进行验证

判断TotalBsmtSF(地下室面积),GrLivArea(居住面积),‘GarageArea’(车库面积)与房价的相关性关系

  • 2.3 与房价相关性强的变量绘制散点图

TotalBsmtSF(地下室面积):与房价似乎有强的线性关系,在右侧有一个异常值存在

fig, ax = plt.subplots()
ax.scatter(x=train.TotalBsmtSF,y=train.SalePrice)
plt.xlabel('TotalBsmtSF')
plt.ylabel('SalePrice')
plt.show()

GrLivArea(居住面积):发现有强的相关关系,在右侧有2个异常点

fig, ax = plt.subplots()
ax.scatter(x=train.GrLivArea,y=train.SalePrice)
plt.xlabel('GrLivArea')
plt.ylabel('SalePrice')
plt.show()

GarageArea(车库面积):发现有正相关关系

fig, ax = plt.subplots()
ax.scatter(x=train.GarageArea,y=train.SalePrice)
plt.xlabel('GarageArea')
plt.ylabel('SalePrice')
plt.show()

'OverallQual'(房屋质量):房价从经验上应该是强相关,可视化进行验证

var = 'OverallQual'
data = pd.concat([train['SalePrice'], 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);

多变量散点图分析


  • 3 . 数据清洗(Data Cleaning)

作图发现房价的分布是右偏的,根据前提假设需要做相应的转换使其符合正态分布

sns.distplot(train['SalePrice'] , fit=norm);

标准化正态分布

#线性的模型需要正态分布的目标值才能发挥最大的作用。
#所以在处理数据时候,需要对数据列进行处理,获取数据列正太分布的均值和标准差。
(miu, sigma) = norm.fit(train['SalePrice'])
#miu = 180932.92 and sigma = 79467.79

检验是否符合标准正太分布

#这是一种检验样本数据概率分布(例如正态分布)的方法。
fig = plt.figure()#创建子图
res = stats.probplot(train[‘SalePrice’], plot=plt) #默认检测是正态分布

我们把该过程并在一起

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

fig = plt.figure()
res = stats.probplot(train['SalePrice'], plot=plt)
plt.show()

将train和test联合起来一起进行数据处理

train_id = train['Id']
test_id = test['Id']
#而对于矩阵来说:shape[0]:表示矩阵的行数;shape[1]:表示矩阵的列数
ntrain = train.shape[0]
ntest = test.shape[0]

y_train = train.SalePrice.values

#合并,reset_index用来重置索引,因复为有时候对制DataFrame做处理后索引可能是乱的。
all_data = pd.concat((train, test)).reset_index(drop=True)

删除SalePrice

all_data.drop(['SalePrice'], axis=1, inplace=True)

ID对预测没有作用,删除ID字段

all_data.drop(['Id'],axis=1,inplace=True)
MSSubClass MSZoning  LotFrontage  ...  YrSold SaleType SaleCondition
0             60       RL         65.0  ...    2008       WD        Normal
1             20       RL         80.0  ...    2007       WD        Normal
2             60       RL         68.0  ...    2008       WD        Normal
3             70       RL         60.0  ...    2006       WD       Abnorml
4             60       RL         84.0  ...    2008       WD        Normal
...          ...      ...          ...  ...     ...      ...           ...
2912         160       RM         21.0  ...    2006       WD        Normal
2913         160       RM         21.0  ...    2006       WD       Abnorml
2914          20       RL        160.0  ...    2006       WD       Abnorml
2915          85       RL         62.0  ...    2006       WD        Normal
2916          60       RL         74.0  ...    2006       WD        Normal

[2917 rows x 79 columns]

查看缺失值比率

all_data_na = (all_data.isnull().sum() / len(all_data)) * 100
#删除缺失值为0的行,并将其按照缺失值降序排列
all_data_na = all_data_na.drop(all_data_na[all_data_na==0].index).sort_values(ascending=False)
#用DateFrame表示
missing_data = pd.DataFrame({'missing_data' : all_data_na})
print(missing_data)
missing_data
PoolQC           99.691464
MiscFeature      96.400411
Alley            93.212204
Fence            80.425094
FireplaceQu      48.680151
LotFrontage      16.660953
GarageFinish      5.450806
GarageQual        5.450806
....

将缺失度用图表的方式展示

f, ax = plt.subplots(figsize=(10, 8))
plt.xticks(rotation='90')
sns.barplot(x=all_data_na.index, y=all_data_na)
plt.xlabel('Features', fontsize=15)
plt.ylabel('Percent of missing values', fontsize=15)
plt.title('Percent missing data by feature', fontsize=15)
plt.show()

对于缺失率在80%以上的特征删除

all_data = all_data.drop('PoolQC', axis=1)
all_data = all_data.drop('MiscFeature', axis=1)
all_data = all_data.drop('Alley', axis=1)
all_data = all_data.drop('Fence', axis=1)

  • 4. 特征工程(Feature Engineering)

特征工程可以说是最重要的步骤了,机器学习大佬吴恩达说过:“数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已”

查看缺失值并分析,填充部分缺失值

missing_data
FireplaceQu      48.680151
LotFrontage      16.660953
GarageFinish      5.450806
GarageCond        5.450806
GarageQual        5.450806
GarageYrBlt       5.450806
GarageType        5.382242
BsmtCond          2.811107
BsmtExposure      2.811107
BsmtQual          2.776826
BsmtFinType2      2.742544
BsmtFinType1      2.708262
MasVnrType        0.822763
MasVnrArea        0.788481
MSZoning          0.137127
BsmtFullBath      0.068564
BsmtHalfBath      0.068564
Utilities         0.068564
Functional        0.068564
GarageCars        0.034282
GarageArea        0.034282
TotalBsmtSF       0.034282
KitchenQual       0.034282
Electrical        0.034282
BsmtUnfSF         0.034282
BsmtFinSF2        0.034282
BsmtFinSF1        0.034282
Exterior2nd       0.034282
Exterior1st       0.034282
SaleType          0.034282
# 对于其他缺失值进行处理, 壁炉为空可能是没有,用none填充
all_data['FireplaceQu'] = all_data['FireplaceQu'].fillna('none')

# LotFrontage代表房屋前街道的长度, 房屋前街道的长度应该和一个街区的房屋相同,可以取同一个街区房屋的街道长度的平均值
all_data['LotFrontage'] = all_data.groupby('Neighborhood')['LotFrontage'].transform(lambda x: x.fillna(x.median()))

# 对于Garage类的4个特征,缺失率一致,一起处理,可能是没有车库,用none填充
for c in ('GarageType', 'GarageFinish', 'GarageQual', 'GarageCond'):
    all_data[c] = all_data[c].fillna('none')

# 对于garage,同样猜测缺失值缺失的原因可能是因为房屋没有车库,连续型变量用0填充
for c in ( 'GarageYrBlt', 'GarageArea', 'GarageCars'):
    all_data[c] = all_data[c].fillna(0)
    
#对于地下室相关的连续变量,缺失同样认为房屋可能是没有地下室,用0填充
for c in ('BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF','TotalBsmtSF', 'BsmtFullBath', 'BsmtHalfBath'):
    all_data[c] = all_data[c].fillna(0)

#地下室相关离散变量,同理用None填充
for c in ('BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2'):
    all_data[c] = all_data[c].fillna('None')
    
# Mas为砖石结构相关变量,缺失值我们同样认为是没有砖石结构,用0和none填补缺失值
all_data["MasVnrType"] = all_data["MasVnrType"].fillna("None")
all_data["MasVnrArea"] = all_data["MasVnrArea"].fillna(0)

#MSZoning代表房屋所处的用地类型,先看下不同取值
all_data.groupby('MSZoning')['MasVnrType'].count().reset_index()
# 由于业务上房屋类型是必须的,一般都有,考虑用众数填充
all_data['MSZoning'] = all_data['MSZoning'].fillna(all_data['MSZoning'].mode()[0])

# 由于数据Functional缺失即为Typ,所以进行填充Typ
all_data["Functional"] = all_data["Functional"].fillna("Typ")

# 对于Utilities,观察到除了一个“NoSeWa”和2个NA之外,所有记录都是“AllPub”,对于房价预测用处很小,删除这个特征
all_data.drop(['Utilities'], axis=1, inplace=True)

查看剩余的缺失值:

all_data_na = (all_data.isnull().sum() / len(all_data)) * 100
all_data_na = all_data_na.drop(all_data_na[all_data_na==0].index).sort_values(ascending=False)[:30]
missing_data = pd.DataFrame({'missing_data' : all_data_na})
missing_data
Exterior1st      0.034282
Exterior2nd      0.034282
Electrical       0.034282
KitchenQual      0.034282
SaleType         0.034282

填充剩余缺失值

for i in ( 'SaleType', 'KitchenQual', 'Electrical', 'Exterior2nd','Exterior1st'):
    all_data[i] = all_data[i].fillna(all_data[i].mode()[0])
Empty DataFrame
Columns: [missing_data]
Index: []
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值