python房价预测

作者: yu930 | 来源:发表于2020-02-29 17:53 被阅读0次

结合已分享的 python 内容,本篇做一次初级的房价数据分析。该数据源于kaggle,是真实的西雅图房产销售数据,提取码: 2w9v,下载的数据内容如下 :

查看数据

拿到数据以后,一般可在 PyCharm 先用 Pandas 预览数据的大小,特征,本例子是csv文件,使用read_csv函数来读取,读进来之后是DataFrame格式

import numpy as np
import pandas as pd
# 读取房价数据
house_price = pd.read_csv('house_data.csv')
# 查看每一列的计数及数据类型等信息
print(house_price.info())

# DataFrame打印时显示所有列
pd.set_option('display.max_columns', None) 
# 查看统计信息
print(house_price.describe())  
# 查看前10行
print(house_price.head(10))

因为文章可看性的原因,打印内容较多这里使用省略号代替,预览情况如下 :

              price     bedrooms  ...     yr_built  yr_renovated
count  4.600000e+03  4600.000000  ...  4600.000000   4600.000000
mean   5.519630e+05     3.400870  ...  1970.786304    808.608261
std    5.638347e+05     0.908848  ...    29.731848    979.414536
min    0.000000e+00     0.000000  ...  1900.000000      0.000000
25%    3.228750e+05     3.000000  ...  1951.000000      0.000000
50%    4.609435e+05     3.000000  ...  1976.000000      0.000000
75%    6.549625e+05     4.000000  ...  1997.000000   1999.000000
max    2.659000e+07     9.000000  ...  2014.000000   2014.000000
<class 'pandas.core.frame.DataFrame'>

RangeIndex: 4600 entries, 0 to 4599
Data columns (total 17 columns):
date             4600 non-null object
price            4600 non-null float64
bedrooms         4600 non-null float64
bathrooms        4600 non-null float64
...
statezip         4600 non-null object
country          4600 non-null object
dtypes: float64(4), int64(9), object(4)

数据分类

处理特征前先根据业务知识筛选出有效特征,城市 / 州的邮编 / 国家 中城市划分房价最细,因此排除州和国家;然后进行分类,一般可分为离散型和连续性;离散型又可分为有序型和无序型

特征 描述 分类
date 销售日期 连续型
price 房屋价格 连续型
bedrooms / bathrooms 房间数量 / 洗手间数量 连续型
sqft_living / sqft_lot 房屋居住面积 / 占地面积 连续型
floors 房屋层数 离散有序型
waterfront 是否临海 离散无序型
view 被看过房次数 离散有序型
condition 房屋评价等级 离散有序型
sqft_above / sqft_basement 地上面积 / 地下室面积 连续型
yr_built / yr_renovated 建筑时间 / 翻新时间 连续型
city / zipcode / country 城市 / 州的邮编 / 国家 离散无序型
#连续型数据,日期为字符串暂不选入
c_features = ['price', 'sqft_living', 'sqft_lot', 'sqft_above', 'sqft_basement', 
              'yr_built', 'yr_renovated'] 
#离散型数据,城市为字符串暂不选入
d_features = ['bedrooms', 'bathrooms', 'floors', 'waterfront', 'view', 'condition']

低方差过滤

若特征的数值变化幅度很小 (连续值方差接近0) 或近乎只有单一值 (离散值多数为同一类),可以认为它对预测的因变量没有影响

# 连续变量的方差,越小越无变化
print(house_price[c_features].std(),'\n')

# 离散变量的类别及数量
for i in d_features:
    print(house_price[i].value_counts(),'\n')

因篇幅只列出了局部打印,从结果可看出数据集变化明显,没有需要忽视的特征

price            563834.702547
sqft_living         963.206916
sqft_lot          35884.436145
sqft_above          862.168977
sqft_basement       464.137228
yr_built             29.731848
yr_renovated        979.414536

1.0    2174
2.0    1811
1.5     444
3.0     128
2.5      41
3.5       2
Name: floors, dtype: int64

0    4140
2     205
3     116
4      70
1      69
Name: view, dtype: int64

数据分布

大多数分析方法是建立在数据集符合正态分布的前提;一般情况下,样本超过30,连续型数据就会呈正态分布,否则说明可能有其他未知因素的影响或取样不随机,使预测结果受影响;
通过.describe()发现该数据集连续型特征存在偏态性,即存在极端值,如max值远大于平均数加上3倍标准差;可以计算偏度、峰度或可视化图表进一步确认;

import seaborn as sns
import matplotlib.pyplot as plt

for i in c_features:
# 计算特征的偏度和峰度,偏度为0、峰值为3符合正态分布
 print(house_price[i].skew())  
 print(house_price[i].kurt()-3)

# 可视化特征数据分布
fig, axes = plt.subplots(2, 4)
fig.set_size_inches(20, 10)
axes = axes.flatten()
for i in n:
    sns.distplot(house_price[i], hist=True, kde=True, ax= axes[n.index(i)])
plt.show()
  • 建筑时间呈不规则分布,可以离散化后,进行相关性分析;
  • 地下室面积、翻新时间呈双峰分布,存在大量 0 值,需分出新特征;
  • 房屋价格、居住面积、占地面积、室内面积有长尾,但大部分子集呈正态分布,可处理离群值后进行相关性分析;
# 更新连续型特征
c_features = ['price', 'sqft_living', 'sqft_lot', 'sqft_above', 'sqft_basement'] 
# 更新离散型特征,新增是否有地下室
d_features = d_features + ['has_basement']

特征清洗

缺失值、离群值等会使某些模型欠拟合或过拟合,通常使用均值代替或删除等方法;上述.describe查看数据时房价存在 0 值和 连续型数据存在长尾,这些都需要判断如何清洗

# 打印出0值房屋的信息进行观察
free_house = house_price.query('price == 0')
print(free_house.describe())
# 没有发现0值的原因,比如建筑年代久远,面积过小等,所以认为是缺失值
house_price = house_price.query('price > 0')

# 可视化房价箱型图,可展示离群值
p = house_price[['price']].boxplot(return_type='dict')
plt.show()
# flies即为异常值的标签,得到离群值的数组
y = p['fliers'][0].get_ydata() 
# 划分出正态分布和离群两部分
p1 = house_price.loc[house_price['price'] > y.min()-1]
p2 = house_price.loc[house_price['price'] < y.min()]

print('P1:\n', p1.describe(), '\n', 'P2:\n', p2.describe())

通过摘要发现离群均价是正常均价的3倍,通常与房价最相关的面积类的数值比也是2~3倍;所以连续型数据未呈正态分布的原因,一定程度与样本非随机有关,如房企有意销售大面积房屋,因此只删除箱型图中严重离群的数值

  • 是否有地下室地下室面积对房价的影响可能是不同的;
  • 没有翻新的房屋可以将建筑时间视为最近一次的翻新时间;
y = np.sort(y)
# 排除掉后20%的离群值
house_price = house_price.loc[house_price['price'] < y[-50]]
# 新增特征,有无地下室
house_price['has_basement'] = house_price['sqft_basement'].apply(lambda x: 1 if x > 0 else 0)
# 补充特征,将建筑时间当作未翻新房屋的翻新时间
house_price.loc[house_price['yr_renovated'] == 0, 'yr_renovated'] = house_price.query('yr_renovated == 0')['yr_built']

相关性分析

如果数个特征之间相关性很高,只取最显著的特征加入模型即可;通常连续型特征之间使用皮尔逊系数,但需要符合正态分布;离散有序型特征使用斯皮尔曼系数等

# 皮尔逊系数热力图,下述左图
sns.heatmap(house_price[c_features].corr('pearson'), vmin=0, vmax=1, annot=True)
plt.show()

# 排除了无地下室房屋后的热力图,下述右图
data = house_price[c_features].query('sqft_basement > 0')
sns.heatmap(data.corr('pearson'), vmin=0, vmax=1, annot=True)
plt.show()

可以清楚的发现房价是与居住面积、室内面积强相关,与地下室面积中相关的;在排除无地下室类型的房屋后,可以发现居住面积、室内面积和地下室面积三者是强相关的,因此只留下居住面积

  • 可以将某些连续型特征离散化后,合并计算相关性系数,如房价、居住面积
  • 分类的间距需有业务根据,如相隔1~10年内建筑的房屋新旧程度相近等;
  • 二值化的离散无序型特征,即只有0和1两种选择,有时也可和有序型合并计算相关性;
# 离散化函数,入参为新特征、需离散化的特征、间距、分类类型和序列位置
def discretization(new_feature, feature, bins, type, id):
    if type == 0:    #type为0使用qcut
        house_price[new_feature] = pd.qcut(house_price[feature],
                                           bins, labels=range(1, bins + 1)).astype(int)
    else:            #type为1使用cut
        house_price[new_feature] = pd.cut(house_price[feature], 
                                          bins, labels=range(1, bins + 1)).astype(int)
    d_features.insert(id, new_feature)   #插入离散值序列时的位置

# 新增四个特征,价格区间、居住面积区间、建筑时间区间、翻新时间区间
discretization('price_rank', 'price', 10, 0, 0)
discretization('sqft_living_rank', 'sqft_living', 10, 0, 1)
discretization('yr_built_rank', 'yr_built', 10, 1, len(d_features))
discretization('yr_renovated_rank', 'yr_renovated', 10, 1, len(d_features))

# 打印斯皮尔曼系数和绘制热力图
print(house_price[d_features].corr('spearman'))
sns.heatmap(house_price[d_features].corr('pearson'), vmin=0, vmax=1, annot=True, annot_kws={"size": 7})
plt.show()

斯皮尔曼系数需对照秩界值表,通常样本超过50时,系数在[0.29, 1]之间,才能证明特征相关;通过热力图可以看出与居住面积相关的特征大概率也与价格有关,且与前者的相关性大于后者;因此只保留居住面积

  • 销售日期通常是与房价无直接关系的,数据集中的日期范围也相对较短;
  • 城市映射的是不同地区房屋单位面积价格的差异,与房价必然相关;
# 取销售月份
house_price['sale_month'] = house_price['date'].apply(lambda x: x[5])
# 计算每月销售的均价
g = house_price.groupby('sale_month').agg({'price':['mean','count']})
print(g)

# 计算各城市面积均价
g = house_price.groupby('city').agg({'price': 'mean', 'sqft_living': 'mean'})
# 根据均价分类
g['city_rank'] = pd.cut(g.eval('price/sqft_living'), 10, labels=range(1, 10+1)).astype(int)
house_price = pd.merge(house_price, g.city_rank, on='city')

验证相关性

可以使用随机森林直接对特征进行筛选,通常可取重要系数超过0.15的特征;但当特征数量庞大时,还是需要依靠上述的步骤预处理减少无效特征

import pydotplus
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor

# 移除重复特征及预测特征
features = c_features+d_features
print(features)
features.remove('sqft_living_rank')
features.remove('price_rank')
features.remove('price')
features.append('city_rank')

# 用于模型的数据集
features = house_price[features]
prices = house_price['price']

# 划分训练集与测试集比为4:1
train_features, test_features, train_prices, test_prices = train_test_split(features, prices, test_size = 0.2, random_state = 42)
# 调用随机森林算法训练模型
rf = RandomForestRegressor(n_estimators=100, random_state=42, max_depth=10)
rf.fit(train_features, train_prices)

#选择其中一个决策树输出dot文件
tree = rf.estimators_[5]
export_graphviz(tree,
                out_file = 'tree.dot',
                feature_names = list(features.columns),
                rounded = True,
                precision = 1)

#将dot文件转化为svg图片文件
graph = pydotplus.graph_from_dot_file('tree.dot')
graph.write_svg('price.svg')

# 打印出值的重要系数
importances = rf.feature_importances_
indices = np.argsort(importances)
print(indices)
for i in indices:
    print ('feasture:'+list(features.columns)[i]+',     importance:', importances[I])

查看重要系数排序,只有居住面积、城市超过了0.15,与之前的分析结果一致

预测模型

本次选择最常用的线形回归模型,因数据集存在部分离群值和某些城市房价样本较少,为了防止过拟合,选取Ridge岭回归

from sklearn.model_selection import train_test_split
from sklearn.linear_model import RidgeCV

# 将城市哑值化,因为各城市的房价系数可能是不同的
features = pd.get_dummies((house_price[['sqft_living', 'city']]))

#  划分训练集与测试集比为4:1
train_features, test_features, train_prices, test_prices = train_test_split(features, prices, test_size = 0.2, random_state = 42)

# 调用岭回归模型训练
lin_reg = RidgeCV()
lin_reg.fit(train_features, train_prices)
# 用测试值预测房价
y_predict = lin_reg.predict(test_features)

# 输出模型分数
print('lin_reg.score: ',lin_reg.score(test_features, test_prices),'\n\n')
# 输出模型的准确率
accuracy_rate = (1-abs(y_predict-test_prices)/test_prices).mean()
print('accuracy_rate: ', accuracy_rate,'\n\n')
# 输出回归系数
print('lin_reg.coef:\n',lin_reg.coef_,'\n')
print('lin_reg.coef: ',lin_reg.intercept_,'\n')

# 实际值的散点图
plt.scatter(house_price['sqft_living'], house_price['price'], color='blue', s=1)
# 将多元线线形映射至一维,预测值的直线图
features = pd.get_dummies((house_price[['sqft_living', 'city']]))
plt.plot(house_price['sqft_living'], lin_reg.predict(features), color='red', linewidth=1)
plt.show()

平均74%的精准率,预测结果一般,可以尝试非线性的模型,或继续优化特征工程

线性归预测结果

相关文章

  • python房价预测

    结合已分享的 python 内容,本篇做一次初级的房价数据分析。该数据源于kaggle,是真实的西雅图房产销售数据...

  • 机器学习-线性回归预测房价模型demo

    这篇介绍的是我在做房价预测模型时的python代码,房价预测在机器学习入门中已经是个经典的题目了,但我发现目前网上...

  • 80. TensorFlow教程(四)房价预测

    本文介绍实战房价预测模型,内容如下: 房价预测模型介绍 使用TensorFlow实现房价预测模型 使用Tensor...

  • python数据挖掘预测Boston房价

    一、数据介绍此数据是一份源于美国某经济学杂志上,分析研究波士顿房价( Boston HousePrice)的数据集...

  • 房价预测

    背景:DC竞赛比赛项目,运用回归模型进行房价预测。数据:主要包括2014年5月至2015年5月美国King Cou...

  • 房价预测

    这周本该有两篇文章,上半周没有完成Kaggle案例,花了一些时间学习了sklearn库。周日了,先早点将下半周的文...

  • kaggle.回归问题.2018-04-16

    详解 Kaggle 房价预测竞赛优胜方案:用 Python 进行全面数据探索Kaggle实战之一回归问题使用skl...

  • ML预测波士顿房价-Udacity nanodegree Bos

    预测波士顿房价。用以往的房价数据来训练模型预测未来的房价。1.加载csv数据;2.探索数据,察看数据的最小值、最大...

  • 动手学深度学习(五) 梯度消失、梯度爆炸

    梯度消失、梯度爆炸以及Kaggle房价预测 梯度消失和梯度爆炸 考虑到环境因素的其他问题 Kaggle房价预测 梯...

  • 梯度消失、梯度爆炸 2020-02-18

    梯度消失、梯度爆炸以及Kaggle房价预测 梯度消失和梯度爆炸 考虑到环境因素的其他问题 Kaggle房价预测 梯...

网友评论

    本文标题:python房价预测

    本文链接:https://www.haomeiwen.com/subject/seygqhtx.html