北京市租房数据分析
北京市房地产租赁市场中进行的有效租房数据分析
临近毕业之际,许多同学纷纷开始关注租房问题.我便利用链家网提供的租房数据展开了研究,并运用机器学习算法对未来租金进行了预测.
通过八爪鱼获取链家北京市13个区的租房数据共计21492条,并将其存储于Excel表格中并呈现如下形式

随后,在对原始数据进行预处理的过程中

接下来基于Jupyter Notebook对数据进行分析,在开始阶段将加载需要用到的库并设定绘图风格等参数;接着加载数据集。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('whitegrid')
#解决画图中显示中文的问题
plt.rcParams['font.sans-serif']=['SimHei']
plt.rc('figure', figsize=(10, 10))
#解决画图中负值显示为方框的问题
plt.rcParams['axes.unicode_minus']=False
#内嵌绘图,可以省略掉plt.show()这一步。
%matplotlib inline
data=pd.read_csv("zufang.csv")
data.info()
data.hist(bins=50,figsize=(15,15))
打印出数据的信息和各数值型特征的分布。


经过分析发现,在所调查的数据集中, 房屋面积主要集中在二百平米以下区域. 租金水平则主要维持在两万元左右. 在深入分析数据特征时, 发现卧室属性归类为object型变量, 而客厅与卫生间等空间属性则被分类为整数型变量. 基于此观察结果, 在后续的数据预处理阶段有必要对卧室属性这一字段的具体取值情况进行进一步考察.
data['bedroom'].unique()
out:array([‘1’, ‘2’, ‘3’, ‘5’, ‘6’, ‘4’, ‘7’, ‘9’, ‘8’, ‘未知’, ‘14’], dtype=object)
我们注意到,在‘bedroom’列中存在‘未知’元素,并找到了这些包含‘未知’值的记录进行处理。
通过筛选出包含‘未知’值的记录并进行剔除。
data[data['bedroom'].isin(['未知'])]

data = data.drop([12548,14064,17881])
将‘bedroom’归类为int64类型,并对拥有卧室数量较多的房子进行调查以发现是否存在不符合常识的数据点,并予以删除
for col in ['bedroom']:
data[col] = data[col].astype(np.int64)
data[data['bedroom'].isin([7,8,9,14])]
从输出中随机提取了一部分数据,在分析过程中发现有一条记录显示该房屋拥有14间卧室但仅有84平方米的面积明显违反常识因此决定剔除该条无效记录并对房间数和浴室数量的相关字段进行同样的筛选处理

添加了每平米租金列,并把数据保存为‘data_clean.csv’.
data['aver_price'] = data.apply(lambda x: x[-1] / x[2], axis=1)
data.to_csv('data_clean.csv', index=False)
从现在开始对数据展开分析
plt.subplots(figsize=(10,8))
sns.barplot(y="district",x='aver_price', data=data)
各区按平方米租金由高到低排列高低梯度分布为:
租金高于120元的区域包括西城区东城区以及海淀区;
租金介于80至110元之间的区域包括朝阳区丰台区和石景山区;
租金低于80元的区域包括亦庄开发区昌平区等

采用小提琴图分析水、电、燃气及楼层对每平米房租的作用。研究表明,在'民水'和'民电'以及具备'有燃气'的房屋中,房租呈现较为集中的特征;而在'商水'及'商电'且缺乏'无燃气'条件的情况下,则呈现较为分散的趋势。进一步观察发现,在非西城区的情况下,'商水'及'商电'类型的房屋租金中位数普遍较高;类似地,在非门头沟地区,'无燃气'房屋的租金水平也显著高于同类情况。此外,在非西城区范围内,'商电'类型的房屋租金水平普遍高于同类情况;同样地,在非南四环地区,'无燃气'房屋的租金水平也显著高于同类情况;而在非北五环地区,'无燃气-无燃气-无燃气-无燃气-无燃气-无燃气-无燃气-无燃气-无燃气-无燃气-无燃气-无燃气-不一致的情况',其租金水平则相对较低。值得注意的是,亦庄、大兴及丰台地区的地下室房价普遍偏低,而其他三类地区的此类房屋则呈现出较高的房价波动性
plt.subplots(figsize=(10,15))
sns.violinplot(x='aver_price',y='district',hue='water',data=data)
plt.subplots(figsize=(10,15))
sns.violinplot(x='aver_price',y='district',hue='gas',data=data)
plt.subplots(figsize=(10,15))
sns.violinplot(x='aver_price',y='district',hue='electricity',data=data)
plt.subplots(figsize=(10,20))
sns.violinplot(x='aver_price',y='district',hue='floor',data=data)




注
haidian=data[data['district'].isin(['海淀'])]
haidian.head()
plt.subplots(figsize=(10,10))
sns.barplot(y="business_area",x='aver_price', data=haidian)

我们深入分析北京市内各个商圈的情况,在租金水平方面进行了详细研究,并分别挑选出租金水平最高的20个商圈和租金水平最低的20个商圈进行重点考察。
shangquang=data.groupby(['business_area'],as_index=False)['aver_price'].mean()
shangquan=shangquang.sort_values(['aver_price'],ascending=False)
#前20
shangquan_top20=shangquan[:20]
plt.subplots(figsize=(8,8))
sns.barplot(y="business_area",x='aver_price', data=shangquan_top20)
#后20
shangquan_last20=shangquan[-21:-1]
plt.subplots(figsize=(8,8))
sns.barplot(y="business_area",x='aver_price', data=shangquan_last20)

通过调查分析,排名靠前的20个商业区中,其平均每平米租金水平普遍达到或超过150元/平方米.值得注意的是,金宝街、东单、东四以及金融街等区域的租金水平达到了或突破了200元/平方米.

我们发现周边20公里范围内的平均单平方米租金都不超过50元,在这个范围内对租房客而言具有较高的性价比。
通过类似分析方法来考察北京市内每平方米租金最高及最低的20个住宅区。
xiaoqu=data.groupby(['community'],as_index=False)['aver_price'].mean()
xiaoqu=xiaoqu.sort_values(['aver_price'],ascending=False)
#前20
xiaoqu_top20=xiaoqu[:20]
plt.subplots(figsize=(8,8))
sns.barplot(y="community",x='aver_price', data=xiaoqu_top20)
#后20
xiaoqu_last20=xiaoqu[-21:-1]
plt.subplots(figsize=(8,8))
sns.barplot(y="community",x='aver_price', data=xiaoqu_last20)


在统计过程中, 我们识别出数量前三名的房型类型, 具体包括(两室一间半厅一间卫生间)、(一间半厅两间一间卫生间)以及(三进院一间一间半卫生间)。
plt.subplots(figsize=(10,20))
sns.countplot(y='house_type', data=data);
本研究关注的是城市区域中地铁周边距离对单平方米租金水平的影响程度。通过使用Python编程语言中的Seaborn库(regplot)构建回归模型,并生成对应的散点图及最佳拟合直线来分析各区域间的租金分布特征。研究结果表明,在多数行政区中(仅除外),随着地铁周边距离的增加(减少),单平方米租金水平呈现下降(上升)的趋势。以上海市与北京市为例:
sns.jointplot(x='subway_distince',y='aver_price',kind='hex',color='k',data=chaoyang)
plt.subplots(figsize=(10,10))
sns.regplot(x='subway_distince',y='aver_price',data=chaoyang)

由于数据数量庞大(超过几千个),导致许多点重叠在一起难以辨认细节。因此我们采用热图来进行可视化分析,在热图中颜色越深表示该区域的数据密度越高,并且有助于深入分析变量之间的相互作用

顺义:
plt.subplots(figsize=(8,8))
sns.regplot(x='subway_distince',y='aver_price',data=shunyi)

在百度地图上对顺义区区域内的住宅区分进行了位置观察后发现,在重点区域的核心地段布局着如IDCITY艾迪城、水木兰亭等高端公寓及别墅社区其租金水平较高从而导致其周边房价出现明显上涨现象这与地理位置呈现正相关关系并且高端社区对整体房价有显著提升作用
data_new=data[data['rent_price']<=20000]
data_new.info()

在‘subway_diatince’这一列中发现了大量缺失值,并通过查看生成图表进行观察得知:链家网仅考虑了离地铁站不超过1200米的数据范围。针对这些缺失值所在区域,并未完全缺乏地铁站点存在感,而是由于距离超过了设定阈值(1200米)。于是本研究随机选择了10个缺失样本案例,在百度地图上确定其到最近地铁站点的实际步行路径长度,并采用加权计算方法得出其平均步行距离约为3公里左右。基于此结果,在原始数据中的NaN标记位置填入该计算结果以替代原有数据缺省情况。
data_new=data_new.fillna(3000)
data_new.info()

注
data_new['room_number']=data_new['bedroom']+data_new['livingroom']+data_new['bathroom']
x=data_new[['type','area','district','subway_distince','business_area','community','floor','water','electricity','gas','bedroom','livingroom','bathroom','house_type','room_number']]
y=data_new["rent_price"]
x=x.to_dict(orient="records")
4.划分数据集:
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=22)
5.特征工程:
用DictVectorizer进行字典特征抽取
from sklearn.feature_extraction import DictVectorizer
transfer=DictVectorizer()
x_train=transfer.fit_transform(x_train)
x_test=transfer.transform(x_test)
基于梯度提升树(GDBT)和随机森林算法构建预测模型:由于决策树属于概率模型,在预测时无需关注特征的具体取值(即无需考虑特征的绝对值),而是主要关注不同类别间的分类分界点。因此,在这类模型中不需要进行数据标准化处理。对于回归问题而言,梯度提升树(GDBT)具有显著优势在于能够处理非线性关系。
from sklearn.ensemble import GradientBoostingRegressor
model_gbr=GradientBoostingRegressor()
model_gbr.fit(x_train,y_train)
mlp_score=model_gbr.score(x_test,y_test)
print(mlp_score)
评分:0.7640728571208095
随机森林:
from sklearn.ensemble import RandomForestRegressor
model_RFR=RandomForestRegressor()
model_RFR.fit(x_train,y_train)
RFR_score=model_RFR.score(x_test,y_test)
print(RFR_score)
评分:0.8412334781347181 可以看出,在未经参数调优的情况下随机森林得分更高。下一步是对GDBT进行参数优化并绘制图表
model_gbr_GridSearch=GradientBoostingRegressor()
param_dict={'n_estimators':[60,90,120,150,180,200],
'learning_rate':[0.01,0.02,0.05,0.1,0.2],
'max_depth':[4,6,8,11],
'min_samples_leaf':[1,2,4,6,8],
'max_features':[0.1,0.3,0.5,0.8]}
from sklearn.model_selection import GridSearchCV
estimator=GridSearchCV(model_gbr_GridSearch,param_grid=param_dict)
estimator.fit(x_train,y_train)
print(estimator.best_params_)
print(estimator.score(x_test,y_test))
输出:{‘n_estimators’: 200, ‘learning_rate’: 0.2, ‘min_samples_leaf’: 1, ‘max_depth’: 11, ‘max_features’: 0.5}
0.8757023147910544
model_best_gbr=GradientBoostingRegressor(learning_rate= 0.2, max_features=0.5, min_samples_leaf=1, max_depth=11, n_estimators= 200)
model_best_gbr.fit(x_train,y_train)
y_predict1=model_best_gbr.predict(x_test)
mlp_score=model_best_gbr.score(x_test,y_test)
print(mlp_score)
#设置大小
fig = plt.figure(figsize=(300,5))
#绘制数据
line1,=plt.plot(range(len(y_test)),y_predict1,'b-',label='gbr',linewidth=2)
line2,=plt.plot(range(len(y_test)),y_test,'r-',label='实际',linewidth=2)
#添加网格线
plt.grid(True,linewidth=2)
#优化图表
fig.tight_layout()
#添加图
plt.legend(handles=[line1,line2])
plt.show()
评分:R^2=0.8731

对随机森林我只调了一下‘n_estimators= 200’。
from sklearn.ensemble import RandomForestRegressor
model_RFR=RandomForestRegressor(n_estimators=200)
model_RFR.fit(x_train,y_train)
RFR_score=model_RFR.score(x_test,y_test)
print(RFR_score)
y_predict2=model_RFR.predict(x_test)
#设置大小
fig = plt.figure(figsize=(300,5))
#绘制数据
line1,=plt.plot(range(len(y_test)),y_predict2,'b-',label='RF',linewidth=2)
line2,=plt.plot(range(len(y_test)),y_test,'r-',label='实际',linewidth=2)
#添加网格线
plt.grid(True,linewidth=2)
#优化图表
fig.tight_layout()
#添加图
plt.legend(handles=[line1,line2])
plt.show()
fig.savefig('./RF.jpg')
评分:0.8627571089788625 选取了RF对比图的一部分,并以红色线条表示实际租金、蓝色线条代表预测租金。观察到预测值与真实值之间的差异较小。该模型表现出良好的适用性。

