安居客二手房房价分析(一)
最近在跟女友讨论未来是去南京还是去杭州发展,虽然两个城市都各有优势,但房价始终是绕不开房价的问题。刚好很久之前写的一个安居客房价爬虫还能用,于是便顺手爬了些数据来做下分析。这里先放几张预览图
数据来源
文章中所用的数据为本人爬取的安居客二手房房价数据。有需要的同学可以自行下载。链接:https://pan.baidu.com/s/193zo6W1RkbOGWRoVyLXV7g 提取码:36iy
如果有同学对房价爬虫感兴趣,后期我会专门开一个爬虫专题。
数据预处理
这里我主要简单介绍下house_info、region这两个字段以及数值的处理。
house_info字段
house_info这个字段里包含了大量的信息,像户型、面积、朝向、装修、楼层、建成年代以及建筑结构,不同信息之间以|相隔开。
我这边利用了df.str.split()
来处理:
data_split['room_type']=data.house_info.str.split("|").str[0].values #户型
data_split['area']=data.house_info.str.split("|").str[1].values #面积
data_split['ort']=data.house_info.str.split("|").str[2].values #朝向
data_split['decorate']=data.house_info.str.split("|").str[3].values #装修
data_split['floor']=data.house_info.str.split("|").str[4].values #楼层
data_split['built_year']=data.house_info.str.split("|").str[5].values #建成年代
data_split['structure']=data.house_info.str.split("|").str[6].values #结构
但这样处理会产生一些问题,如建成年代的缺失,会导致数据移位。
因此,这里的处理思路为:若structure字段为空值,则以built_year中的值来进行填充。
#处理数据移位
data_split['structure'].fillna(data_split['built_year'], inplace=True)
data_split['built_year']=data_split.built_year.map(lambda x : x if '年' in x else np.nan)
region字段
某个房源,对于我这个外地人而言,可能更想知道它属于南京的哪个行政区,而不是什么凤凰新街这之类的地名。为此,这里我需要对房源的行政区划进行重新匹配。
这里我是借助百度地图的API接口,以小区名+region+城市名作为查询关键词,实现了行政区的匹配。这部分的脚本目前在工作机上,之后也会一并放上来。
数值处理
为了方便进行数值分析,这里利用正则来提取字符串里的数值。
#定义数值提取函数
def value_extract(string):
pattern1=r"[1-9]\d*.\d*|0.\d*[1-9]\d*"
pattern2=r"[1-9]\d*"
try:
result=float(re.findall(pattern1,string)[0])
except:
try:
result=int(re.findall(pattern2,string)[0])
except:
result=np.nan
return result
#提取数值数据
data_split['total_floors']=data_split.floor.map(lambda x: value_extract(x))
data_split['area']=data_split.area.map(lambda x: value_extract(x))
data_split['built_year']=data_split.built_year.map(lambda x: value_extract(x))
其他还有一些细节上的处理,如楼层处理,这里不再一一赘述。处理之后的数据如下所示:
以下是数据预处理部分的完整代码:
import pandas as pd
import numpy as np
import copy
import re
data=pd.read_excel('E:\\pycharm_file\\pycharmfile\\fangjia\\南京二手房.xlsx',index_col=[0])
#处理house_info
data_split=copy.deepcopy(data)
data_split.drop(['house_info'],axis=1,inplace=True)
data_split['room_type']=data.house_info.str.split("|").str[0].values #户型
data_split['area']=data.house_info.str.split("|").str[1].values #面积
data_split['ort']=data.house_info.str.split("|").str[2].values #朝向
data_split['decorate']=data.house_info.str.split("|").str[3].values #装修
data_split['floor']=data.house_info.str.split("|").str[4].values #楼层
data_split['built_year']=data.house_info.str.split("|").str[5].values #建成年代
data_split['structure']=data.house_info.str.split("|").str[6].values #结构
#处理数据移位
data_split['structure'].fillna(data_split['built_year'], inplace=True)
data_split['built_year']=data_split.built_year.map(lambda x : x if '年' in x else np.nan)
#处理楼层数据
data_split['floor_type']=data_split.floor.str.split("(").str[0].values
data_split['total_floors']=data_split.floor.str.split("(").str[1].values
#处理均价数据
data_split['av_price']=data_split.av_price.str.split("元").str[0].values
#data_split.head()
#import re
#定义数值提取函数
def value_extract(string):
pattern1=r"[1-9]\d*.\d*|0.\d*[1-9]\d*"
pattern2=r"[1-9]\d*"
try:
result=float(re.findall(pattern1,string)[0])
except:
try:
result=int(re.findall(pattern2,string)[0])
except:
result=np.nan
return result
#提取数值数据
data_split['total_floors']=data_split.floor.map(lambda x: value_extract(x))
data_split['area']=data_split.area.map(lambda x: value_extract(x))
data_split['built_year']=data_split.built_year.map(lambda x: value_extract(x))
#处理均价数据
n=data_split.shape[0]
result=[]
for i in range(n):
str_list=data_split.av_price.str.split(',').get(i)
result.append(str_list[0]+str_list[1])
data_split['av_price']=result
#删除无用的列
data_split.drop(['floor'],axis=1,inplace=True)
#转化数据类型
data_split.av_price=data_split.av_price.astype('int')
#处理floor_type
data_split.floor_type=data_split.floor_type.astype('string')
data_split['floor_type']=data_split.floor_type.map(lambda x: x.strip())
def floor_judge(num):
if num>=10:
return '高楼层'
elif num >=6:
return '中楼层'
else:
return '低楼层'
for i in range(data_split.shape[0]):
if '楼' in data_split.iloc[i,14]:
continue
else:
data_split.iloc[i,14]=floor_judge(data_split.iloc[i,15])
data_split.head()