数据集及源码 [ 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数据预处理
-
主要关注金额,日期等字段的处理
-
把握整体样本量,后续合理采样
-
将城区变量转换为中文
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 变量描述性分析
-
因变量 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)#没啥关系
部分结果: 

连续变量,相关分析: 注意点:
-
直方图呈现右偏,进行取对数操作
-
第一次对y取对数后|r|反而降了,所以将x也取对数
-
最后的达到的效果要使在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)
-
描述性统计结束,提出我们的假设(学区房贵,靠近地铁贵。。。。),后面就开始假设检验分析,验证结论
四、建模
-
采样:根据城区分层抽样,每区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]之间 """
-
方差分析逐个检查分类变量的解释力度 注意点:对于分类变量回归分析加上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 万元
好贵啊。。。(〒︿〒)
本文通过描述性统计分析探讨房价的影响因素,并建立预测模型。利用实际数据集,对多个变量进行了详细分析,包括区域、学区房等因素对房价的影响。通过线性回归、取对数线性模型等手段逐步优化模型,最终实现对特定条件下的房价预测。
414





