分析思路
- 1 导入数据
- 2 数据清洗
- 3 数据分析
3.1 各城区房源数量分布
3.2 各城区总面积和平均面积分布
- 3.2.1 各城区总面积分布
- 3.2.2 各城区平均面积分布
- 3.2.3 全市平均面积分布
3.3 各城区总价和单价分布
-3.3.1 总价分布
-3.3.2 单价分布
-3.3.3 总价和单价排名前十小区
3.4 房价与户型、楼层、朝向、建筑年代关系的分析
-3.4.1 房价与户型的关系
-3.4.2 房价与楼层的关系
-3.4.3 房价与朝向的关系
-3.4.4 房价与建筑年代的关系
(本文所用数据会放在文章最后,请需要者自取)
分析过程如下:
1.导入数据
导入pandas和numpy包,读取二手房数据并查看前五行数据
import numpy as np
import pandas as pd
df = pd.read_csv('链家二手房.csv',engine='python')
df.head()
因为含中文字符的列名在处理时比较麻烦,所以在这里将其列名更改为英文字符
df=df.rename(columns={'小区名称':'village','户型':'house_type','面积':'area','区域':'district','朝向':'orientations','价格(W)':'total_price','单价(平方米)':'unit_price','建筑时间':'construction_time','楼层':'floor'})
查看数据类型及缺失情况
df.info()
df.isnull().sum()
2.数据清洗
由上面数据预览可知,应将floor列分成两列以便后续分析使用,故在此将其分成两列并查看前五行数据:
df1=pd.concat([df,df['floor'].str.split('/',expand=True)],axis=1)
df1.head()
删除floor列,重命名得到的两列:
#删除多余列
del df1['floor']
#重命名得到的两列
df1.rename(columns={0:'floor_level',1:'floor'},inplace=True)
df1.head()
提取construction_time和floor字段中的数字,查看前十行数据和数据类型:
df1['construction_time']=df1['construction_time'].str.extract('(\d+)年建')
df1['floor']=df1['floor'].str.extract('(\d+)层')
df1.head()
df1.dtypes
由上面查看字段类型可知,construction_time和floor两个字段数据类型为object,将其转化为float:
df1['construction_time']=df1['construction_time'].astype(float)
df1['floor']=df1['floor'].astype(float)
查看数据描述性统计:
df1.describe()
由以上描述性统计结果可以得到如下信息:
1.面积平均值为96㎡,面积中位数为85㎡,说明少数大面积的房源拉高了的总体平均水平
2.总价平均值为580万,总价中位数为430万,情况与上面一样,少数总价高的房源拉高了总体的平均水平
3.单价平均数为59725元,单价中位数为58068元,平均值与中位数基本相等,说明房价升高趋势比较线性
查看数据缺失情况:
df1.isnull().sum()
由上可知,orientations字段缺失行数为1355,construction_time字段缺失行数为6216,floor字段缺失行数为755,这些缺失值在下面对其进行分析时再加以处理
3.数据分析
上海各区行政地图以及等级划分:
上海市区共分为三个等级:
1、黄浦区、长宁区;
2、静安区、徐汇区;
3、杨浦区、虹口区、普陀区。
上海郊区共分为三个等级:
1、宝山区、闵行区;
2、松江区、嘉定区、青浦区;
3、奉贤区、崇明区、金山区。
3.1各城区房源数量分布
district_number=df1.district.value_counts().reset_index().sort_values(by='district',ascending=False)
district_number
可视化:
plt.figure(figsize=(9,4))
plt.bar(district_number['index'],district_number.district)
plt.title('各城区房源数量')
由以上柱状图分析可知,除了静安区、金山区和崇明区房源数量不到50以外,其他14个城区二手房数量均在1300套以上,数量最多的为浦东区,共有2599套
3.2 各城区总面积和平均面积分布
3.2.1 各城区总面积分布
导入可视化包matplotlib:
%matplotlib inline
import matplotlib.pyplot as plt
# 正常显示中文设置
plt.rcParams['font.sans-serif']=['SimHei']
# 正常显示正负号设置
plt.rcParams['axes.unicode_minus']=False
因为静安、崇明、金山三个区的房源量较小,数据无法代表整体水平,所以在这里删除这三个区的数据 将各区组成一个列表并删除上述三个区:
dis_list=list(df1.district.drop_duplicates())
dis_list.remove('静安')
dis_list.remove('崇明')
dis_list.remove('金山')
dis_list
删除上述三个区并查看删除后数据的前五行:
df2=df1[df1.district.isin(dis_list)]
df2.head()
计算各城区二手房源总面积:
grouped=df2.groupby('district')
grouped_total_area=grouped['area'].sum().reset_index().sort_values(by='area',ascending=False)
grouped_total_area
可视化:作出各城区总面积折线图
plt.figure(figsize=(12,5))
plt.plot(grouped_total_area.district,grouped_total_area.area)
plt.title('各城区总面积分布')
由上图可知,总面积排名前三位的分别是:青浦、松江和浦东,这得益于它们较大的面积
3.2.2 各城区平均面积分布
grouped=df2.groupby('district')
grouped_area=grouped['area'].mean().reset_index().sort_values(by='area',ascending=False)
grouped_area
可视化:作出各城区平均面积折线图
x=grouped_area.district
y=grouped_area['area']
# 设置画布大小
plt.figure(figsize=(9,4))
plt.plot(x,y)
plt.title('各城区平均面积分布')
以上折线图显示,青浦区总面积和平均面积远远大于其他城区平均面积,青浦区共有房源1769套,数量较大,不太可能出现异常,故分析可能原因为:不在中心位置,建设成本较低,房屋设计面积较大。
各城区总面积和平均面积趋势大致一样,各城区平均面积在[77,116]之间,其中,面积在[100,116]之间的为松江、黄埔和金山,面积在[90,100)之间的为奉贤、长宁、闵行和静安,面积在[80,90)之间的为嘉定、虹口、崇明、浦东、闸北、宝山、普陀和徐汇,杨浦区平均面积为77.8㎡。
3.2.3 全市平均面积分布
以区间[0,50)、[50,100)、[100,150)、[150,200)、[200,+∞)为划分标准,将面积划分为tinysmall、small、medium、big、huge五个等级,分别对应极小户型、小户型、中等户型、大户型和巨大户型。
df2.loc[(df2.area>=0)&(df2.area<50),'area_level']='tinysmall'
df2.loc[(df2.area>=50)&(df2.area<100),'area_level']='small'
df2.loc[(df2.area>=100)&(df2.area<150),'area_level']='medium'
df2.loc[(df2.area>=150)&(df2.area<200),'area_level']='big'
df2.loc[df2.area>=200,'area_level']='huge'
求出各户型的数量:
grouped_area_level=df2.groupby('area_level').total_price.count().reset_index()
grouped_area_level
可视化:作出各户型数量柱状图
plt.figure(figsize=(8,5))
plt.bar(grouped_area_level.area_level,grouped_area_level.total_price)
plt.title('各户型数量分布')
由上图可知:
1.平均面积为small的房源数量占总数的50%,即一半房源的面积在区间[50,100]㎡,
2.平均面积为medium的房源数量占总数的25%,即四分之一的房源面积在区间[100,150]㎡,
3.平均面积为tinysmall的房源数量占总数的17%,即17%的房源面积在区间[0,50]㎡
3.3 各城区总价和单价分布
3.3.1 总价分布
# 把分区后的总价组成一个字典,以便下面将它转化为dataframe
good=dict(list(df2.groupby('district')['total_price']))
# 转化为dataframe
gooddf=pd.DataFrame(good)
# 作出总价箱线图
plt.figure(figsize=(12,5))
gooddf.boxplot()
plt.ylim(0,3000)
plt.title('各城区总价箱线图')
各城区总价平均值排名:
由以上结果可知,
总价No.1的为黄浦区,平均值为1059.3万,总价区间跨越大,总体价格价格区间为[500,1300]万,中位数小于平均值,故少数价格高的拉高总体平均值的现象比较严重
总价No.2的为长宁区,平均值为760.8万,总体价格区间为[400,1000]万,中位数接近平均值,总价上升比较线性
总价No.3的为徐汇区,平均值为671.8万,总体价格区间为[400,800]万,中位数小于平均值,故少数价格高的拉高了总体平均值
总价No.4的为青浦区,平均值为676.0万,总价价格区间为[300,750]万,中位数远小于平均值,故少数价格高的拉高总体平均值的现象比较严重
平均总价分布:
plt.hist(df2.total_price,bins=20)
plt.title('平均总价分布直方图')
房屋总价是一个左凸的直方图,90%的数据集中在[500,1000]的区间,即90%的房源总价在500万到1000万之间,只有大概10%的房源属于极高的价格,这个结果符合现实的房价分布
3.3.2 各城区单价分布
good1=dict(list(df2.groupby('district')['unit_price']))
good1df=pd.DataFrame(good1)
plt.figure(figsize=(12,5))
good1df.boxplot()
plt.ylim(0,150000)
plt.title('各城区单价分布箱线图')
各城区单价排名:
df2.groupby('district')['unit_price'].mean().reset_index().sort_values(by='unit_price',ascending=False)
由以上结果可知,
单价No.1的是黄浦,平均值为90666元,大体价格区间为[78000,100000]元
单价No.2的是徐汇,平均值为79157元,大体价格区间为[69111,90000]元
单价No.3的是长宁,平均值为75081元,大体价格区间为[66000,84000]元
全市单价分布:
plt.hist(df2.unit_price,bins=20)
plt.title('全市单价分布直方图')
单价直方图接近正态分布,该图显示70%的单价集中在区间[30000,90000]元,符合房价的现实分布规律
3.3.3 总价和单价排名前十小区
对小区进行分组,计算出各小区房源数量,并按照房源数量降序的顺序排序
df3=df2.groupby('village').total_price.count().reset_index().sort_values(by='total_price',ascending=False)
df3.head()
因为很多小区房源数量太少,其统计值不具有代表性,故在此过滤掉房源数量小于20的小区
# 过滤房源数量小于20的小区
df4=df3[df3.total_price>20]
df4.village.head(10)
提取房源数量大于20的小区的数据
df5=df2[df.village.isin(df4.village)]
df5.head()
计算各小区总价排名前十的小区:
totalp_village=df5.groupby('village').total_price.mean().sort_values(ascending=False).head(10).reset_index()
totalp_village
可视化:作出平均总价排名前十小区的平均总价柱状图
plt.figure(figsize=(15,5))
plt.bar(totalp_village.village,totalp_village.total_price)
plt.title('平均总价排名前十的小区')
总价排名前十的小区如上图所示,第一名为翠湖天地御苑,平均总价超过4000万,是第二名尚海湾豪庭的两倍,查询了解到,该小区位于上海市的心脏地带,真可谓寸土寸金
计算单价排名前十的小区
totalp_village1=df5.groupby('village').unit_price.mean().sort_values(ascending=False).head(10).reset_index()
totalp_village1
可视化:作出平均单价排名前十小区的单价柱状图
plt.figure(figsize=(15,5))
plt.bar(totalp_village1.village,totalp_village1.unit_price)
plt.title('平均单价排名前十的小区')
由上图可知,排名前三位的小区分别是翠湖天地御苑、东方曼哈顿和融创滨江壹号院,翠湖天地御苑的平均单价最高,超过了150000元,高于排名第二的东方曼哈顿近40000元
3.4 房价与户型、楼层、朝向、建筑年代的关系
3.4.1 房价与户型的关系
按户型进行分组,计算出每个户型的房源数量,过滤掉房源数量小于100的户型
# 计算各户型的数量
grouped_house_type=df2.groupby('house_type').total_price.count().sort_values(ascending=False).reset_index()
# 过滤房源数量小于100的户型
grouped_house_type2=grouped_house_type.loc[grouped_house_type.total_price>100]
grouped_house_type2
可视化:作出数量柱状图
由数量柱状图可知,数量排名前四的分别为:2室2厅、2室1厅、3室2厅和1室1厅,他们数量均在3000套以上,远大于其后面户型的数量,这说明小户型的房屋数量较多,这也符合上海人多地少的现状,所以小户型房屋较多以满足一般收入家庭的需要。
计算数量大于100的户型列表:
e_list=grouped_house_type2.house_type
e_list
提取上述户型的数据并查看前5行:
df10=df2[df2.house_type.isin(e_list)]
df10.head()
计算各户型平均单价:
计算各户型的平均单价:
grouped_house_type3=df10.groupby('house_type').unit_price.mean().reset_index().sort_index(by='unit_price',ascending=False)
grouped_house_type3
可视化:作出各户型的单价柱状图:
plt.figure(figsize=(15,5))
plt.bar(grouped_house_type3.house_type,grouped_house_type3.unit_price)
plt.title('户型-房价')
由上图可知,单价排名前三的户型分别为1室2厅、2室0厅、1室0厅。可以看出,小户型的房屋比较受欢迎,因为其总价一般较低,经济压力较小,故而成为热门户型,这也导致了这些户型价格的上涨,使得小户型的房屋单价高于大户型的房屋。
3.4.2 房价与楼层的关系
计算各个楼层等级的房源数量
a_list=list(['高区','中区','低区'])
df6=df2[df2.floor_level.isin(a_list)]
grouped_floor_level=df6.groupby('floor_level').unit_price.count().reset_index()
grouped_floor_level
可视化:并作出其柱状图
plt.title('楼层等级-数量')
plt.bar(grouped_floor_level.floor_level,grouped_floor_level.unit_price)
由上图可知,低、中、高区的房源数量基本相等,都在8000套以上,其中高区最多,数量超过10000套
计算各楼层等级的平均总价
grouped_floor_level1=df6.groupby('floor_level').total_price.mean().reset_index()
grouped_floor_level1
可视化:作出其柱状图
plt.title('楼层等级—平均总价')
plt.bar(grouped_floor_level1.floor_level,grouped_floor_level1.total_price)
由上图可知,低、中、高区楼层平均总价均超过500万,其中低区总价最高,为590万
计算各等级楼层平均单价
grouped_floor_level2=df6.groupby('floor_level').unit_price.mean().reset_index()
grouped_floor_level2
可视化:作出其柱状图
plt.title('楼层等级—平均单价')
plt.bar(grouped_floor_level2.floor_level,grouped_floor_level2.unit_price)
由上图可知,低、中、高区平均单价基本相等,均在60000元附近
查看数据的缺失情况:
df2.isnull().sum()
处理floor字段中的缺失值:
# 填充floor列中的空值为999
df2.floor=df2.floor.fillna('999')
# 找出floor列中值为999的行号
c_list=df2[df2.floor=='999'].index.tolist()
# 删除上面查找到的行
df8=df2.drop(c_list)
df8.isnull().sum()
由上可知,floor字段中空值所在的行已被全部删除
计算楼层平均单价排名前十位
# 楼层平均单价排名前十位
df8.groupby('floor').unit_price.mean().sort_values(ascending=False).head(10)
计算各楼层单价平均值,并作出其折线图:
plt.figure(figsize=(15,5))
df8.groupby('floor').unit_price.mean().plot()
plt.title('楼层数-单价')
由上图分析可知,随着楼层输的增加,房价也随之升高。在37层之前,房价随楼层数增加而增加的趋势比较线性,但是在这之后房价随楼层数增加而增加的趋势波动很大,可能的原因是楼层数超过40的住宅数量较小,超过40层的数据量比较小,容易产生误差
3.4.3 房价与朝向的关系
b_list=list(['朝东','朝东北','朝东南','朝东西','朝北','朝南','朝南北','朝西','朝西北','朝西南'])
df7=df2[df2.orientations.isin(b_list)]
grouped_orientations=df7.groupby('orientations').unit_price.mean().reset_index().sort_values(by='unit_price')
grouped_orientations
可视化:作出其柱状图
plt.figure(figsize=(12,5))
plt.bar(grouped_orientations.orientations,grouped_orientations.unit_price)
plt.title('朝向—单价')
由上图可知,朝向对房价有一定的影响,朝向南面(南、东南、西南)的房子总体价格会高一点。这一现象也符合生活情景,朝向南面的房屋采光会比较好,这些南北通透的房子单价相对于其他朝向会高一些。
3.4.4 房价与建筑年代的关系
查看数据缺失情况:
df2.isnull().sum()
删除construction_time字段中缺失的行:
# 填充construction_time字段中的空值为123
df2.construction_time=df2.construction_time.fillna('123')
# 找出construction_time字段中值为123的行号
d_list=df2[df2.construction_time=='123'].index.tolist()
# 删除construction_time列中的空值
df9=df2.drop(d_list)
计算各个年份建造房屋的数量 ,作出其折线图:
plt.figure(figsize=(15,5))
df9.groupby('construction_time').unit_price.count().plot()
plt.title('建筑时间-数量')
以上折线图呈右侧双峰形态,即分别在1995年和2005年左右出现了两个房屋修建的高峰期,这期间房屋数量陡增
计算各个年份平均总价,作出其折线图:
plt.figure(figsize=(15,5))
df9.groupby('construction_time').total_price.mean().plot()
plt.title('建筑时间-平均总价')
计算各个年份平均单价,作出其折线图:
plt.figure(figsize=(15,5))
df9.groupby('construction_time').unit_price.mean().plot()
plt.title('建筑时间-平均单价')
由以上分析可知,
- 以上平均总价与建筑时间的趋势和平均单价与建筑时间的趋势大致一致,都呈现左侧单峰形态。在1920年到1950年间建造的房屋,其总价和单价均高于之后建造的房屋,分析其原因为:在1920年到1950年间建造的房屋,因为建造时间早,其建造的位置处于现在上海的核心地带,因为其土地的稀有性,故而导致了现在的高房价。
- 从2015年以来修建的房屋呈现陡然上升的趋势,这也和目前房价不断升高的趋势契合,这表明房价在短时间内不会出现大的下跌,是否会出现下一个房价高峰,我们拭目以待。