【python数据分析】练习4:线性回归—二手房价预测

数据集及源码 [ https://github.com/JCATHoney/python-data-analysis

](https://github.com/JCATHoney/python-data-analysis)

一、问题描述

在对房价的影响因素进行模型研究之前,首先对各变量进行描述性分析,以初步判断房价的影响因素,进而建立房价预测模型

总体步骤如下: (一) 因变量分析:单位面积房价分析

(二) 自变量分析: 2.1 自变量自身分布分析 2.2 自变量对因变量影响分析

(三)建立房价预测模型 3.1 线性回归模型 3.2 对因变量取对数的线性模型 3.3 考虑交互项的对数线性

(四)预测: 假设有一家三口,父母为了能让孩子在东城区上学,想买一套邻近地铁的两居室,面积是70平方米,中层楼层,那么房价大约是多少呢?

二、数据集

研究二手房价的影响因素,建立房价预测模型,数据存放在“sndHsPr.csv”中。

变量说明如下:

变量含义
dist所在区
roomnum室的数量
halls厅的数量
AREA房屋面积
floor楼层
subway是否临近地铁
school是否学区房
price平米单价

三、描述性统计

3.1数据预处理

  1. 主要关注金额,日期等字段的处理

  2. 把握整体样本量,后续合理采样

  3. 将城区变量转换为中文

    import pandas as pd
    import numpy as np
    import math
    import matplotlib.pyplot as plt
    import matplotlib
    import seaborn as sns
    import statsmodels.api as sm
    from numpy import corrcoef,array
    #from IPython.display import HTML, display
    from statsmodels.formula.api import ols
    import os
    os.chdir(r"C:\Users\Away\Desktop\笔记\数据分析")
    # In[1]:
    import pandas as pd
    mdata = pd.read_csv(r'sndHsPr.csv')
    mdata.head()
    #%%
    #1、描述性统计数据预处理阶段
    describe=mdata.describe()#价格基本情况
    # count     16210.000000
    # mean      61151.810919
    # std       22293.358147
    # min       18348.000000
    # 25%       42812.250000
    # 50%       57473.000000
    # 75%       76099.750000
    # max      149871.000000
    print(mdata.shape[0])#数据量:16210  这里为什么要统计数据量呢?因为做检验时数据量不能过大,一般不超过5000,否则p值会失效
    #%%
    ## 1、描述性统计
    #数据简单处理,重点关注价格日期等字段
    #查看各个字段基本情况
    data0 = mdata
    describe=data0.describe(include="all").T
    #print(data0.dtypes)
    #价格转换为万元
    data0.price = data0.price/10000
    #type_dict = {'借':'out','贷':'income'}
    #card_t3['type1'] = card_t3.t_type.map(type_dict)
    #将区域名转换为中文
    dist_dict = {
            'chaoyang' : "朝阳",
            'dongcheng' : "东城",
            'fengtai' :  "丰台",
            'haidian' : "海淀",
            'shijingshan' : "石景山",
            'xicheng': "西城"
            }
    
    data0['dist']=data0.dist.map(dist_dict)

_中文和负号的显示: _

    matplotlib.rcParams['axes.unicode_minus']=False#解决保存图像时负号'-'显示为方块的问题
    plt.rcParams['font.sans-serif'] = ['SimHei']#指定默认字体 ,解决不能显示中文字体的问题#

3.2 变量描述性分析

  1. 因变量 price

    #因变量图形(主要看看形态)
    data0.price.plot(kind='hist',bins=20,color='lightblue')#右偏严重
    plt.xlabel("单位面积房价(万元/平方米)")
    plt.ylabel("频数")
    print(data0.price.agg(['mean','median','std']))  #查看price的均值、中位数和标准差等更多信息
    print(data0.price.quantile([0.25,0.5,0.75]))
    pd.concat([(data0[data0.price==min(data0.price)]),(data0[data0.price==max(data0.price)])])#查看房价最高和最低的两条观测

2.自变量

  • 首先对自变量进行分类,同一类的统一分析(for)

  • 除了AREA(房屋面积),都是分类变量。

分类变量,主要用条形图、盒须图

    ##1.2、自变量描述(除了房屋面积都是分类变量)
    for i in range(7):
        if i!=3:
            print(data0.columns.values[i],":")
            print(data0[data0.columns.values[i]].agg(['value_counts']).T)
            print('==================================')
        else:
            continue
    print('AREA:')
    print(data0.AREA.agg(['min','mean','max','median','std']).T)
    #%%
    #1.2.1 dist 区域 多分类变量
    #频次统计
    data0.dist.value_counts().plot(kind='bar')
    #%%
    #不同城区的房价
    data0.price.groupby(data0.dist).mean().sort_values(ascending=True).plot(kind='barh')#能看出来和城区还是有关系的
    #%%
    data1 = data0[['dist','price']]
    sns.boxplot(x='dist',y='price',data=data1)
    #dat1.boxplot(by='dist',patch_artist=True)
    plt.ylabel("单位面积房价(万元/平方米)")
    plt.xlabel("城区")
    plt.title("城区对房价的分组箱线图")#城区还是有明显影响的
    #%%
    #1.2.2 roomnum 卧室数-roomnum 多分类
    data2=data0[['roomnum','price']]
    data2.price.groupby(data2.roomnum).mean().plot(kind='bar')
    #data2.boxplot(by='roomnum',patch_artist=True)# patch_artist    是否填充箱体的颜色;
    plt.figure()
    sns.boxplot(x='roomnum',y='price',data=data2)#没啥关系

部分结果: 在这里插入图片描述在这里插入图片描述

连续变量,相关分析: 注意点:

  1. 直方图呈现右偏,进行取对数操作

  2. 第一次对y取对数后|r|反而降了,所以将x也取对数

  3. 最后的达到的效果要使在x,y两个方向都是呈现正态分布

    # 1.2.7 AREA 连续变量
    dataA=data0[['AREA','price']]
    plt.scatter(dataA.AREA,dataA.price,marker='.')#发散型,右偏-对Y取对数
    # area,price都是连续变量,进行相关分析
    xg1=dataA[['price','AREA']].corr(method='pearson')#返回一个dataframe#  r=-0.074 中度负相关。
    #对Y取对数
    dataA['price_ln'] = np.log(dataA['price'])
    plt.figure(figsize=(8,8))
    plt.scatter(dataA.AREA,dataA.price_ln,marker='.')
    plt.ylabel("单位面积房价(取对数后)")
    plt.xlabel("面积(平方米)")#小户型贵
    #求AREA_ln和price_ln的相关系数
    xg3=dataA[['price_ln','AREA']].corr(method='pearson')#|r|=0.058
    #房屋面积和单位面积房价(取对数后)的散点图
    dataA['price_ln'] = np.log(dataA['price'])  #对price取对数
    dataA['AREA_ln'] = np.log(dataA['AREA'])  #对price取对数
    plt.figure(figsize=(8,8))
    plt.scatter(dataA.AREA_ln,dataA.price_ln,marker='.')
    plt.ylabel("单位面积房价(取对数后)")
    plt.xlabel("面积(平方米)")
    #求AREA_ln和price_ln的相关系数矩阵
    data1=array(dataA['price_ln'])
    data2=array(dataA['AREA_ln'])
    datB=array([data1,data2])
    corrcoef(datB)# 0.09,高度相关,且x,y两个方向都是正态分布

初始散点图 在这里插入图片描述 对x,y取对数后的散点图: 在这里插入图片描述

  • 目前结论: 明显影响:区,地铁,学区 不明显:客厅,楼层 基本不影响:卧室(roomnum)

  • 描述性统计结束,提出我们的假设(学区房贵,靠近地铁贵。。。。),后面就开始假设检验分析,验证结论

四、建模

  1. 采样:根据城区分层抽样,每区400,定阈值

    data_new = get_sample(data0,sampling='stratified',k=400,stratified_col=['dist'])
    #2400个样本,阈值确定原则如下:
    """大致原则如下(自然科学取值偏小、社会科学取值偏大):
    n<100 alfa取值[0.05,0.2]之间
    100<n<500 alfa取值[0.01,0.1]之间
    500<n<3000 alfa取值[0.001,0.05]之间
    """
  1. 方差分析逐个检查分类变量的解释力度 注意点:对于分类变量回归分析加上C(分类变量),否则自动识别为连续变量。但是也可以自己创建哑变量(自己选择基准)

    #逐个检查分类变量的解释力度,方差分析
    import statsmodels.api as sm
    from statsmodels.formula.api import ols
    print("dist的P值为:%.4f" %sm.stats.anova_lm(ols('price ~ C(dist)',data=data_new).fit())._values[0][4])
    print("roomnum的P值为:%.4f" %sm.stats.anova_lm(ols('price ~ C(roomnum)',data=data_new).fit())._values[0][4])#明显高于0.001->不显著->独立
    print("halls的P值为:%.4f" %sm.stats.anova_lm(ols('price ~ C(halls)',data=data_new).fit())._values[0][4])#高于0.001->边际显著->暂时考虑
    print("floor的P值为:%.4f" %sm.stats.anova_lm(ols('price ~ C(floor)',data=data_new).fit())._values[0][4])#高于0.001->边际显著->暂时考虑
    print("subway的P值为:%.4f" %sm.stats.anova_lm(ols('price ~ C(subway)',data=data_new).fit())._values[0][4])
    print("school的P值为:%.4f" %sm.stats.anova_lm(ols('price ~ C(school)',data=data_new).fit())._values[0][4])
    '''
    dist的P值为:0.0000
    roomnum的P值为:0.1014 #去掉roomnum,其他保留
    halls的P值为:0.0002
    floor的P值为:0.0013
    subway的P值为:0.0000
    school的P值为:0.0000
    '''
  • 结果处理: 去掉roomnum 对与不太显著的变量“halls”做因子化处理变成二分变量

    #%%
    # 厅数和楼层的影响不太显著。对于厅数可以做因子化处理,变成二分变量('有厅','无厅')
    data_new['hall_new'] = data_new.halls
    data_new.hall_new[data_new.hall_new>0]='有厅'
    data_new.hall_new[data_new.hall_new==0]='无厅'

3、线性回归模型

    # 3 线性回归模型
    lm1 = ols("price ~ C(dist)+school+subway+C(floor)+C(hall_new)++AREA", data=data_new).fit()#这里也可以自己设计基准创建哑变量
    lm1_summary = lm1.summary()
    lm1_summary  #回归结果展示1 R方=0.599 开始忘了加hall_new 发现加了对模型没啥改进作用
  • 残差分析

    #初始线性回归模型残差分析
    data_new['pred1']=lm1.predict(data_new)#模型预测结果
    data_new['resid1']=lm1.resid#取残差
    data_new.plot('pred1','resid1',kind='scatter')  #模型诊断图,存在异方差现象,对因变量取对数
    #预测值增加,残差呈现喇叭口发散状况。考虑取对数

改进前残差分析,异方差现象 在这里插入图片描述 3.1取对数的线性模型

    # 3.1 改进取对数后再次建模
    data_new['price_ln'] = np.log(data_new['price'])
    data_new['AREA_ln'] = np.log(data_new['AREA'])
    lm2 = ols("price_ln ~ C(dist)+school+subway+C(floor)+AREA_ln", data=data_new).fit()
    lm2_summary = lm2.summary()
    lm2_summary  #回归结果展示2 R方=0.614 有一丢丢提升
    #%%
    #残差分析
    data_new['pred2']=lm2.predict(data_new)#模型预测结果
    data_new['resid2']=lm2.resid#取残差
    data_new.plot('pred2','resid2',kind='scatter')  

异方差现象改善 在这里插入图片描述 3.2 加上交互项的非线性模型

  • 思考:为什么要叫交互项? 各个因变量对自变量的影响也不是独立的,比如采样分析后发现石景上区的学区房比非学区房还便宜,与其他地方都相反。地区这个变量就和学区这个变量之间有交互作用*

    schools=['石景山','丰台','朝阳','东城','海淀','西城']
    for i in schools:
        print(i+'非学区房\t',round(data_new[(data_new['dist']==i)&(data_new['school']==0)]['price'].mean(),2),'万元/平方米\t',i+'学区房\t',round(data_new[(data_new['dist']==i)&(data_new['school']==1)]['price'].mean(),2),'万元/平方米')
    
    # 3.2 加上交互项对数模型
    lm3 = ols("price_ln ~ C(dist)*school+subway+C(floor)+AREA_ln", data=data_new).fit()
    lm3_summary = lm3.summary()
    lm3_summary  #回归结果展示 R方=0.618

预测

    #选一个好的模型来做预测
    x_new1=data_new.head(1)
    x_new1
    #%%
    x_new1['dist']='东城'
    x_new1['roomnum']=2
    x_new1['AREA_ln']=np.log(80)
    x_new1['subway']=1
    x_new1['school']=1
    x_new1['floor']='middle'
    x_new1['hall_new']="有厅"
    
    #%%
    #预测值
    print("单位面积房价:",round(math.exp(lm5.predict(x_new1)),2),"万元/平方米")
    print("总价:",round(math.exp(lm5.predict(x_new1))*70,2),"万元")
                       

结果: 单位面积房价: 7.8 万元/平方米 总价: 545.99 万元

好贵啊。。。(〒︿〒)

  • 0
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值