• Python案例|使用Scikit-learn进行房屋租金回归分析


    图片

    回归分析是一种预测性的建模技术,研究的是因变量(目标)和自变量(预测器)之间的关系。回归分析是建模和分析数据的重要工具。比如预测股票价格走势、预测居民收入、预测微博互动量等等。常用的有线性回归、逻辑回归、岭回归等。本文主要使用线性回归。

    01、案例导入:房屋租金回归分析

    本文使用的租房数据集是经过 前一篇 数据预处理后的“北京链家网”租房数据集,数据存储在newbj_lianJia.csv文件中,共4322条数据。每条数据包含房屋的详细信息:ID、楼层(floor)、有无电梯(lift)、城区名(district)、街道名(street)、小区名(community)、面积(area)、房屋朝向(toward)、户型(model)、总楼层(totalfloor)和租金(rent)信息,共计11个属性。房屋详细信息如图1所示。

    图片

    ■图1 租房数据集的部分数据展示

    本案例任务要求:找到数据表中的特征属性与房屋租金(rent)的关系,并使用线性回归模型对租金进行回归分析。

    02、案例实现

    “北京链家网”租房数据的租金回归分析的实现流程为:首先导入数据,对数据进行预处理;然后讨论租金与其他属性是否存在线性关系;接下来对房屋面积和租金建立线性回归模型;最后评估回归模型的效果。具体实现过程如下。

    (1) 导入库。其中LabelEncoder模块用于数据预处理时对非数值型数据进行数字化,train_test_split模块将数据集划分为训练集和测试集,linear_model模块用于构建线性模型。代码如下。

    1. import pandas as pd
    2. import numpy as np
    3. import matplotlib.pyplot as pltfrom sklearn.preprocessing
    4. import LabelEncoderfrom sklearn.model selection
    5. import train test splitfrom sklearn import linear model

    (2) 读入数据,并对数据做预处理。

    ①读入数据。使用Pandas库的read_csv()读入“北京链家网”的租房数据集newbj_lianJia.csv。读入数据表的10列数据分别是:楼层(floor)、有无电梯(lift)、城区名(district)、街道名(street)、小区名(community)、面积(area)、房屋朝向(toward)、户型(model)、总楼层(totalfloor)和租金(rent)。代码如下。

    1. dfl=pd.read csv('newbi lianJia.csv', header=0,
    2. usecols=[1, 2,3,45,6,7,8,910],encoding='gbk')print(df1)

     输出结果为:

    1. floor lift district ... rent totalfloor
    2. 0 中楼层 无 房山 ... 3500.00 6
    3. 1 低楼层 有 顺义 ... 5400.00 17
    4. 2 中楼层 无 大兴 ... 3800.00 6
    5. ...
    6. 4319 中楼层 有 朝阳 ... 8000.00 8
    7. 4320 高楼层 有 朝阳 ... 9000.00 28
    8. 4321 低楼层 无 怀柔 ... 18000.00 2
    9. [4322 rows x 10 columns]

     

    ② 重复值处理和缺失值处理。上一篇,我们已经对数据集进行了重复值和缺失值处理,所以本章使用的数据集不存在重复行和缺失值。

    ③ 分解户型model列数据。将model列的取值“*室*厅*卫”拆分为3个列:bedroom、livingroom和bathroom,分别对应室、厅和卫。具体来说,首先定义3个函数,分别获取室、厅和卫的数据,然后使用Pandas库的map()方法将3个函数应用于数据表的model列。代码如下。

    1. def apart room(x):
    2. ...
    3. 分割字符串,提取"室"
    4. ...
    5. room=x.split(室')[0]
    6. return int(room)
    7. def apart hal1(x):
    8. ...
    9. 分割字符串,提取"厅"
    10. ...
    11. hall=x.split('')[o].split('')[1]return int(hall)
    12. def apart wc(x):
    13. ...
    14. 分割字符串,提取"卫"
    15. ...
    16. wc=x.split('')[o].split('')[1]return int(wc)dfl['bedroom']=df1['model'].map(apart room)dfl['livingroom']=dfl['model'].map(apart hall)dfl['bathroom =dfl model ].map(apart wc)dfl.drop(columns=['model'],inplace=True) #删除原数据集中的 model 列

    ④ 数据编码。回归分析或某些机器学习算法是基于数学函数的,这些算法的输入要求是数值型数据,所以如果数据集中出现了非数值型数据,数据分析的结果可能是不理想的。例如,在本章所使用的租房数据集中,楼层floor这个属性有4个取值,即地下室、低楼层、中楼层和高楼层,这时需要将4个属性值转换为数值型数据。可以自行编写程序,将非数值型数据转换成数值型数据,也可以使用Scikit-learn库提供的两种方法:LabelEncoder 和 OneHotEncoder。

    LabelEncoder又称为标签编码,例如将楼层floor的4个取值(地下室、低楼层、中楼层和高楼层)转换为数值0、1、2、3,这就是标签编码。OneHotEncoder又称为独热编码,将每一个非数值型变量的m个可能的取值转变成m个0或1,对于每一个变量,这m个值中仅有一个值为1,其他的都为0,例如使用OneHotEncoder方法将楼层floor编码为4位0或1的数值:地下室=>1000、低楼层=>0100、中楼层=>0010、高楼层=>0001。利用OneHotEncoder将非数值型数据转为0和1,有利于提升计算速度。但是这种编码方式增加了数据维度,比如原楼层属性只有一列数据,如果按照OneHotEncoder编码,数据列变成了4列数据。所以如果需要编码的属性的取值数目不多,建议优先考虑OneHotEncoder,如果取值数目较多,使用OneHotEncoder会使特征空间变得非常大,所以此时不建议使用OneHotEncoder。

    本文对属性取值比较少的floor和lift两个属性进行自定义编码,对属性取值比较多的district、street、community和toward属性使用LabelEncoder编码。OneHotEncoder方法大家可自行练习。代码如下。

    1. #对 floor 和 lift 属性进行自定义编码
    2. map1=['地下室':0'低楼层 :1,'中楼层 :2'高楼层':3)
    3. dfl['floor =dfll'floor'].map(map1)
    4. map2={'未知':3,"有':1'无':2)
    5. dfl 'lift'=dfl 'lift .map(map2)
    6. #对 district、street,community和 toward 属性使用 LabelEncoder 进行编码
    7. labelE=LabelEncoder()
    8. labelE.fit(dfl['district'])
    9. dfl['district']=labelE.transform(dfl['district'])labelE.fit(dfll'street'])
    10. dfl['street']=labelE.transform(dfl 'street'])labelE.fit(df1'community'])
    11. dfl['community']=labelE.transform(dfl['community'])labelE.fit(df1 toward')
    12. dfl['toward']=labelE.transform(dfl['toward'])

    将重新编码后的数据保存为rent.csv文件。代码如下。

    df1.to csv('rent.csv',index= False)

    最终,数据处理后的数据如图3所示。

    ■图3 数据预处理后的房屋租金数据集展示

    (3) 分析特征属性与租金是否有线性关系。将数据预处理后,新的数据集的特征属性变为12个,如图8-3所示。这些特征属性不一定与租金有线性关系。为了提高线性回归模型的预测效果,本章只使用与租金有较强线性关系的属性作为特征属性来预测租金。判定这11个特征属性中哪些属性与租金有线性关系,下面给出两种方法。

    ① 第一种方法:画出所有特征属性与租金分布的散点图,通过可视化比较直观地判断是否存在线性关系。实现代码如下。

    1. df2=df1.drop(columns=L'rent!y=df1['rent'].values
    2. colname=df2.columns
    3. plt.rcParams 'font.sans-serifr=SimHeir
    4. plt.figure(figsize=(18,20)) # 调整字体设置
    5. plt.subplots adjust(wspace=0)
    6. xlabel dicts=["floor";"楼层","lift":"有无电梯","district""城区名","street""街道名","community":"小区名","area":"面积","toward":"房屋朝向","totalfloor":总楼层","bedroom":"卧室数""livingroom":"客厅数”,"bathroom":"卫生间数”}
    7. #设置图中特征属性名为中文
    8. for i in range(11):
    9. plt.subplot(6,2,i+1)
    10. plt.scatter(df2[colname [i]],y)
    11. plt.xlabel(xlabel dicts colname i]])
    12. plt.ylabel(租金/元 )
    13. plt.tight layout ()
    14. plt.show()

     代码使用循环结构将11个特征属性与租金的散点图分别画在11个子图中,如图4所示。从图中可以看出,只有area这个属性和rent存在线性相关关系。

    图片

     

    ■ 图4 数据集中特征属性和租金的散点分布图

    ② 第二种方法:使用相关系数判定。Pandas提供了corr()方法计算变量之间的相关性,该方法的返回值范围为[-1,1],0表示两个变量不相关,正值表示正相关,负值表示负相关,绝对值越大,相关性越强。实现代码如下,结果如图5所示。

    1. corr=dfl[['floor','lift','district','street','community','area','toward'
    2. totalfloor','bedroom','livingroom','bathroom','rent']].corr()
    3. print(corr)

    ■ 图5 数据表中属性之间的相关系数

    从图5可以看出,只有area属性和rent存在较强的线性相关关系。

    根据以上两种方法的结果,选择area作为特征属性与租金建立线性回归模型。

    (4) 建立线性回归模型。

    ① 读取特征列数据和目标列数据。使用area作为特征列,目标列为rent。代码如下。

    1. x=dfl 'area'
    2. y=dfl['rent
    3. x=np.array([x]).T
    4. y=np.array(Ly]) .T

     ② 将数据集划分为训练集和测试集。在sklearn.model_selection中导入train_test_split()方法,从样本中按比例选取训练集和测试集。train_test_split()方法的语法如下。

    train test split(x,,test size=None, train size=None, random state=None)

     

    参数说明如下。

    ●x:待划分的特征数据。

    ●y:待划分的目标数据。

    ●test_size:定义测试集大小。如果是0.0到1.0之间的浮点数,则表示用于测试样本的占比,如果是整数,则表示样本的数量。

    ●train_size:定义训练集大小,类似于test_size。使用train_test_split()方法时,应该提供train_size或test_size。如果两者都没有给出,则用于测试的数据集的默认占比为0.25。

    ●random_state:随机数的种子,在划分数据集时控制随机化。它可以是None或一个整数,如果random_state等于None,则每次产生的训练集和测试集的划分结果不同。如果在重复试验时需要得到相同的划分数据集,则将random_state设置为非0的整数。

    本文按照8∶2的比例将数据集划分为训练集和测试集,其中,test_size=0.2,random_state设置为1。

    1. x train, x test, y train, y test = train test split(x, y, random state=l, test
    2. size=0.20)

    ③ 构建线性回归模型,并输出线性方程。代码如下。

    1. lr=linear model.LinearRegression()
    2. lr.fit(x train,y train)
    3. #截距 b
    4. b=lr.intercept_
    5. #斜率 k
    6. k=lr.coef
    7. print(线性方程的截距为: ,b)
    8. print(线性方程的斜率为: ,k)
    9. #输出线性回归方程
    10. print('rent=','(',round(k[0,0],2),')','*','area','+','', round(b[o],2),')')

    输出结果为:

    1. 线性方程的截距为:[-2030.20533106]
    2. 线性方程的斜率为:[117.9376802377]
    3. rent=(117.94) * area + (-2030.21)

    ④ 画出训练数据的线性拟合图,通过可视化比较直观地看到线性拟合的效果。代码如下。

    1. plt.rcParams['font.sans-serif'] =['SimHei'] # 调整字体设置
    2. plt.plot(x train,y train,'k.')
    3. yl=k*x train + b
    4. plt.plot(x train,yl,'r-')
    5. plt.xlabel('面积')
    6. plt.ylabel(租金/元 )
    7. plt.show()
    图6 房屋租金数据集的线性拟合

     

     (5) 回归模型的评价。使用测试集对回归模型进行评价,本章使用决定系数作为衡量回归模型效果好坏的指标。这里调用了线性回归对象的score()方法和sklearn.metrics模块下的r2_score()方法。代码如下。

    1. from sklearn.metrics import r2 scorey
    2. pred test=lr.predict(x test)
    3. print("测试集的决定系数=:.3f}".format(lr.score(x test,y test)))
    4. print("测试集的决定系数={:.3f)"format(r2 score(y test,y pred test)))

    输出结果为:

    1. 测试集的决定系数=0.584
    2. 测试集的决定系数=0.584

    可以看出,score()和r2_score()方法的输出结果是一致的,这表明Scikit-learn库的score()方法使用了“决定系数”这一指标。决定系数越接近于1,说明模型的数据拟合性越好,反之,决定系数越接近于0,表明模型的数据拟合度越差。

    如果测试集和训练集的决定系数值差别比较大,则表明训练的回归模型可能存在一定问题。将回归模型应用于训练集,输出决定系数值。代码如下。

    print("训练集的决定系数={:.3f}".format(lr.score(x train,y_train)))

     输出结果为:

    训练集的决定系数=0.591

    从运行结果可以看出,训练集合的决定系数(0.591) 略高于测试集合的决定系数(0.584),这是符合预期的。

  • 相关阅读:
    基于大模型GPT,如何提炼出优质的Prompt
    C# 后端以form格式请求上传附件
    数字经济时代 企业的数据安全需要多维考虑
    数据集学习笔记(六):目标检测和图像分割标注软件介绍和使用,并转换成YOLO系列可使用的数据集格式
    C++中queue的用法(超详细,入门必看)
    springboot整合webSocket(看完即入门)
    青少年近视问题不容小觑,蔡司用专业技术助力孩子视力健康发展
    nuxt.js + vue-i18n + nuxt-i18n 实现多语言国际化
    微信小程序中使用画布canvas实现动态心电图绘制
    2022年高教社杯全国大学生数学建模竞赛-A题:波浪能最大输出功率设计(附MATLAB代码)
  • 原文地址:https://blog.csdn.net/qq_41640218/article/details/131930527