Advertisement

二手房房价预测案例 -- 代码实现

阅读量:

本篇将继续上一篇二手房房价预测案例 -- 基本概念以及模型应用之后进行代码实现,这两部分构成了一个简单的数据分析流程。结合两篇文章通过数据分析和挖掘的方法实现二手房价格预测的预测后,分析报告请看这里

一.数据说明

1.数据字段名称及字段含义

复制代码
 '''

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

数据举例如图:

2.导入分析所需python模块

复制代码
 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 statsmodels.formula.api import ols

二、导入分析数据

1.获取房价数据

复制代码
 datall=pd.read_csv(r"D:\EVAN\Python\practice\sndHsPr.csv")  '读入清洗过后的数据'

    
 print("%d",datall.shape[0])

2.查看数据基本描述

复制代码
 dat0=datall

    
 dat0.describe(include="all").T

将价格单位换算成万元,将城区的水平由拼音改成中文,以便作图输出美观

复制代码
 dat0.price=dat0.price/10000

    
 dict1 = {
    
     u'chaoyang' : "朝阳",
    
     u'dongcheng' : "东城",
    
     u'fengtai' :  "丰台",
    
     u'haidian' : "海淀",
    
     u'shijingshan' : "石景山",
    
     u'xicheng': "西城"
    
     }  
    
 dat0.dist = dat0.dist.apply(lambda x : dict1[x])
    
 dat0.head() '查看前五项数据'

三、变量分析

根据上一章的基本概念的解释,分析思路如下。

1.1 因变量

price

复制代码
 matplotlib.rcParams['axes.unicode_minus']=False "解决保存图像时负号'-'显示为方块的问题"

    
 plt.rcParams['font.sans-serif'] = ['SimHei']"指定默认字体"
    
 dat0.price.hist(bins=20)'因变量直方图'
    
 plt.xlabel("单位面积房价(万元/平方米)")
    
 plt.ylabel("频数")
复制代码
 '查看price的均值、中位数和标准差等特征'

    
 print(dat0.price.agg(['mean','median','std']))  
    
 print(dat0.price.quantile([0.25,0.5,0.75]))
复制代码
 '查看房价最高和最低的两条观测'

    
 pd.concat([(dat0[dat0.price==min(dat0.price)]),(dat0[dat0.price==max(dat0.price)])])

1.2 自变量:
dist+roomnum+halls+floor+subway+school+AREA

整体来看

复制代码
 for i in range(7):

    
     if i != 3:
    
         print(dat0.columns.values[i],":")
    
         print(dat0[dat0.columns.values[i]].agg(['value_counts']).T)
    
         print("=======================================================================")
    
     else:
    
         continue
    
 print('AREA:')
    
 print(dat0.AREA.agg(['min','mean','median','max','std']).T)

2 建模:

首先检验每个解释变量是否和被解释变量独立,由于原始样本量太大,无法使用基于P值的构建模型的方案,因此按照区进行分层抽样

复制代码
 def get_sample(df, sampling="simple_random", k=1, stratified_col=None):

    
     """
    
     对输入的 dataframe 进行抽样的函数
    
   5.     参数:
    
     - df: 输入的数据框 pandas.dataframe 对象
    
   8.         - sampling:抽样方法 str
    
         可选值有 ["simple_random", "stratified", "systematic"]
    
         按顺序分别为: 简单随机抽样、分层抽样、系统抽样
    
   12.         - k: 抽样个数或抽样比例 int or float
    
         (int, 则必须大于0; float, 则必须在区间(0,1)中)
    
         如果 0 < k < 1 , 则 k 表示抽样对于总体的比例
    
         如果 k >= 1 , 则 k 表示抽样的个数;当为分层抽样时,代表每层的样本量
    
   17.         - stratified_col: 需要分层的列名的列表 list
    
         只有在分层抽样时才生效
    
   20.     返回值:
    
     pandas.dataframe 对象, 抽样结果
    
     """
    
     import random
    
     import pandas as pd
    
     from functools import reduce
    
     import numpy as np
    
     import math
    
     
    
     len_df = len(df)
    
     if k <= 0:
    
     raise AssertionError("k不能为负数")
    
     elif k >= 1:
    
     assert isinstance(k, int), "选择抽样个数时, k必须为正整数"
    
     sample_by_n=True
    
     if sampling is "stratified":
    
         alln=k*df.groupby(by=stratified_col)[stratified_col[0]].count().count() # 有问题的
    
         #alln=k*df[stratified_col].value_counts().count() 
    
         if alln >= len_df:
    
             raise AssertionError("请确认k乘以层数不能超过总样本量")
    
     else:
    
     sample_by_n=False
    
     if sampling in ("simple_random", "systematic"):
    
         k = math.ceil(len_df * k)
    
     
    
     #print(k)
    
  
    
     if sampling is "simple_random":
    
     print("使用简单随机抽样")
    
     idx = random.sample(range(len_df), k)
    
     res_df = df.iloc[idx,:].copy()
    
     return res_df
    
  
    
     elif sampling is "systematic":
    
     print("使用系统抽样")
    
     step = len_df // k+1          #step=len_df//k-1
    
     start = 0                  #start=0
    
     idx = range(len_df)[start::step]  #idx=range(len_df+1)[start::step]
    
     res_df = df.iloc[idx,:].copy()
    
     #print("k=%d,step=%d,idx=%d"%(k,step,len(idx)))
    
     return res_df
    
  
    
     elif sampling is "stratified":
    
     assert stratified_col is not None, "请传入包含需要分层的列名的列表"
    
     assert all(np.in1d(stratified_col, df.columns)), "请检查输入的列名"
    
     
    
     grouped = df.groupby(by=stratified_col)[stratified_col[0]].count()
    
     if sample_by_n==True:
    
         group_k = grouped.map(lambda x:k)
    
     else:
    
         group_k = grouped.map(lambda x: math.ceil(x * k))
    
     
    
     res_df = df.head(0)
    
     for df_idx in group_k.index:
    
         df1=df
    
         if len(stratified_col)==1:
    
             df1=df1[df1[stratified_col[0]]==df_idx]
    
         else:
    
             for i in range(len(df_idx)):
    
                 df1=df1[df1[stratified_col[i]]==df_idx[i]]
    
         idx = random.sample(range(len(df1)), group_k[df_idx])
    
         group_df = df1.iloc[idx,:].copy()
    
         res_df = res_df.append(group_df)
    
     return res_df
    
  
    
     else:
    
     raise AssertionError("sampling is illegal")

生成的哑变量与其他所需变量合并成新的数据框

复制代码
 dat1=pd.concat([data,dat01[['school','subway','style_new','roomnum','AREA','price']]],axis=1)

    
 dat1.head()

3.1 线性回归模型 -- 最小二乘线性(OLS)线性回归模型

复制代码
 lm1 = ols("price ~ dist_丰台+dist_朝阳+dist_东城+dist_海淀+dist_西城+school+subway+

    
 floor_middle+floor_low+style_new+roomnum+AREA", data=dat1).fit()
    
 lm1_summary = lm1.summary()
    
 lm1_summary

3.2 有交互项的对数线性模型,城区和学区之间的交互作用

交互作用的解释

复制代码
 schools=['丰台','朝阳','东城','海淀','西城']

    
 print('石景山非学区房\t',round(dat0[(dat0['dist']=='石景山')&(dat0['school']==0)]['price'].mean(),2),'万元/平方米\t',
    
      '石景山学区房\t',round(dat0[(dat0['dist']=='石景山')&(dat0['school']==1)]['price'].mean(),2),'万元/平方米')
    
 print('-------------------------------------------------------------------------')
    
 for i in schools:
    
     print(i+'非学区房\t',round(dat1[(dat1['dist_'+i]==1)&(dat1['school']==0)]['price'].mean(),2),'万元/平方米\t',i+'学区房\t',round(dat1[(dat1['dist_'+i]==1)&(dat1['school']==1)]['price'].mean(),2),'万元/平方米')

假想情形,做预测,x_new是新的自变量

复制代码
 x_new1=dat1.head(1)

    
 x_new1
    
 x_new1['dist_朝阳']=0
    
 x_new1['dist_东城']=1
    
 x_new1['roomnum']=2
    
 x_new1['halls']=1
    
 x_new1['AREA_ln']=np.log(70)
    
 x_new1['subway']=1
    
 x_new1['school']=1
    
 x_new1['style_new']="有厅"

预测值

复制代码
 print("单位面积房价:",round(math.exp(lm3.predict(x_new1)),2),"万元/平方米")

    
 print("总价:",round(math.exp(lm3.predict(x_new1))*70,2),"万元")

关键代码都展示完了,总的来说,重点的流程如下。接下来,需要输出分析报告

全部评论 (0)

还没有任何评论哟~