深圳租房分析第二弹
之前从网上爬取了一份深圳的租房数据,并且从统计分析和可视化的角度进行了分析。今天还是使用之前的数据进行数据分析和建模,以及模型的可解释性探索。本文的主要内容包含:
导入库
导入主要的库用于:数据处理、可视化、建模、特征可解释性等
数据基本信息
1、导入数据
2、数据形状和字段类型
下面是具体的特征解释:
1 | # 下面是特征属性 |
3、查看数据的缺失值情况
使用的是df.isnull().sum()
来查看:在time字段中存在6个缺失值
4、缺失值填充
由于缺失量比较少,直接在网上搜索到相应的时间进行了人工填充:先定位缺失值的位置,再进行填充
字段预处理
name
小区的姓名name直接删除
1 | df.drop("name",axis=1,inplace=True) |
layout
layout分成3个具体的属性:室、厅、卫
特殊情况:当layout为"商铺"时,直接删除~
使用正则解析出室厅卫:
1 | df1 = df["layout"].str.extract(r'(?P<shi>\d)室(?P<ting>\d)厅(?P<wei>\d)卫') |
location
不同朝向的房子数量:
1 | df["location"].value_counts() |
小结:可以看到,在朝南北、朝南、朝北的房子数量比较多,而且整体的价格分布更为广泛。
对不同朝向的房子实施硬编码:
1 | # 自定义的顺序:根据朝向和价格的关系图(上面) |
size和sizeInside
建筑面积和套内面积提取出数值部分,提供两种方法:
1 | # 1、通过切割的方式来提取 |
zhuangxiu
1 | df["zhuangxiu"].value_counts() |
主观意义上的思路:毛坯的等级最低,豪装最高。下面实施硬编码过程:
1 | # 硬编码 |
1 | df["zhuangxiu"] = df["zhuangxiu"].map(zhuangxiu) |
numberFloor
中低高楼层和价格money之间的关系
1 | # 提取中低高楼层 |
小结:中低高3个楼层在房租上面的影响稍小。直接考虑独热编码的方式:
1 | df = (df.join(pd.get_dummies(df["numberFloor"])) |
1 | df.drop("numberFloor",axis=1,inplace=True) # 删除原字段 |
time
房子的建成时间处理:
1 | df["time"].value_counts() |
提取时间年份:
1 | df["time"] = df["time"].str.extract(r'(?P<time>\d+)') |
zone+position
行政区域和地理位置的合并处理
1 | df["zone"].value_counts() |
1 | # 合并字段 |
不同行政区域不同地理位置下的价格均值统计:
1 | zone_position_mean = |
根据合并的zone_position_mean数据框中的money
来进行硬编码:福田_车公庙 是最高位
1 | zone_position = zone_position_mean["zone_position"].tolist()[::-1] |
way
出租方式和价格的关系探索:
1 | fig = px.violin(df,y="money",color="way") |
从way的取值来看:大部分的房子是愿意整租的,而且押一付一和押二付一最为普遍。提取出“整租”和“合租”两种方式:
1 | df["way"] = df["way"].apply(lambda x: x.split(" ")[0]) |
终于:算是得到一份比较符合建模的数据
样本不均衡
我们查看way字段下的数据情况:明显way=1的取值情况是远远大于way=0。
解决方法:使用SMOTE算法来解决解决way=0过少的问题。
1 | x = df.drop("way",axis=1) |
解决之后的way=1和way=0的样本相同
字段异常处理
1、填充样本后发现某些应该是整数,却出现了小数,比如:wei和time等
1 | cols = ["shi","ting","wei","time"] |
2、类型转化
1 | # 转变数据类型 |
相关性分析
相关系数
针对上面得到的smote_df数据进行下面的相关性分析:
1 | # 保存了再读取 |
1、相关性
能够直观看到money因变量和size与sizeInside相关性很强
1 | corr = df.corr() |
相关系数排序
单个属性和money之间的相关性大小排序,可以看到:size(房子面积)、sizeInsize(套内面积)和wei(卫)的相关型比较强。
单纯地从相关系数得到的结论,还是有待考证~
自变量和因变量关系
上面举出3个字段和money之间的相关性,在最右侧:
- size和sizeInside相对集中的时候,money高频出现0-25000之间
- 在不同的money取值情况,wei字段的取值集中在1-4之间
建模
特征归一化
下面是针对数据的归一化过程,采用的MinMaxScaler方法:
1 | X = df.drop("money",axis=1) |
数据集切分
按照训练集:测试集 = 8:2的比例进行数据集的划分:
1 | from sklearn.model_selection import train_test_split |
特征选择
在前面的工作我们从相关系数和因变量的相关性大小进行了比较,发现:Size、sizeInside和wei是比较相关的系数。
下面是从使用mutual_info_classif来查看每个特征的重要性:
1 | from sklearn.feature_selection import mutual_info_classif |
我们发现:shi、wei、zhuangxiu、size都是比较重要的特征
评价指标
1 | from sklearn.metrics import r2_score,mean_absolute_error,mean_squared_error |
引入多种回归模型:
1 | # 线性回归 |
不同模型效果
重点关注模型的r2值
1、线性回归-LinearRegression
2、决策树回归-DecisionTreeRegressor
3、随机森林回归-RandomForestRegressor
4、梯度提升回归-GradientBoostingRegressor
通过3种回归模型的r2得分比较:GradientBoostingRegressor > DecisionTreeRegressor > RandomForestRegressor > LinearRegression
模型可解释分析
为了更好理解机器学习模型的输出,下面使用SHAP库来探索调参后随机森林模型的可解释性。通过pip install shap
即可安装
随机森林调参
1 | # 随机搜索调优 |
进行fit拟合之后便得到了最优的参数组合:
1 | rf_random.best_params_ |
调参后随机森林模型的r2系数略优于调参前:
建立最佳参数下的模型:
1 | rf_random = RandomForestRegressor( |
计算shap_values
SHAP value最大的优势是SHAP能对于反映出每一个样本中的特征的影响力,而且还能够表现出影响的正负性。
在SHAP中进行模型解释需要先创建一个explainer,SHAP支持很多类型的explainer
1 | # 1、传入调优模型rf_random创建explainer |
均值对比
1、通过模型预测得到的均值求解
1 | # y的预测值和真实值比较 |
其中:money-真实值,pred-随机森林模型的预测值。得到的均值为:
1 | # 真实的平均值 |
2、通过SHAP得到的基准值base_value
1 | # shap得到的基准值 |
整体特征重要性
取出每个特征的shap值的绝对值的平均值作为该特征的重要性,得到水平的条形图:
1 | shap.summary_plot(shap_values, |
1 | shap.summary_plot(shap_values, X_test) |
可以看到,通过shap值来看:
- size面积、zone_position区域位置、shi房间数 的重要性才是最靠前的,这个结果可以和相关系数的大小进行对比
- 前5个特征中,蓝点主要还是集中在SHAP值小于0的区域
单个样本的SHAP值
从数据中随机抽查一条样本查看shap值:
1 | i=18 |
- 第一列是特征名称
- 第二列是特征的具体数值
- 第三列是各个特征在该样本中对应的SHAP值
注意:一个样本中各特征 SHAP 值的和加上基线值应该等于该样本的预测值
单条样本的特征可视化:
1 | # 可视化 |
红色表示higher部分:表明针对这条数据,zone_position和size是重要的特征。下面是换了另一个样本的结果:
不同的样本具有不同的重要属性
部分依赖图-Partial Dependence Plot
1、单个变量的影响
1 | shap.dependence_plot('size', |
通过图形我们观察到:size的取值在0.4以下,size的shap都是相对平和。一旦size达到一定值,对房租价格的拉升作用相当明显。
2、两个变量的交互式影响
SHAP同样能够查看两个变量的交互式影响,比如size和zone_position。
1 | shap.dependence_plot( |
当指定了interaction_index 的取值情况,我们不仅能够观察到size和房租的关系,还可以看到size和zone_position之间存在的关系:size在分界点(大致在0.4)前后,one_position的相应都比较大(红色),这同时表明zone_position是一个重要性高的特征~