鏈家二手房數據鏈接:https://pan.baidu.com/s/1ZLT30nyCPTbx1_ISW5fMCg 提取碼:8a2y
這是我第二篇數據分析項目實戰,當凌晨一點分析結束后深刻體會到學以致用的重要性、接觸實戰項目的重要性。
因為按照我的學習計劃只練習一篇實戰項目即"cd用戶消費行為分析",不過……慶幸的是在朋友的影響下練習了本項目,并進一步了解python第三方庫。
在開篇之前附上數據分析思路
1、數據的清洗
導入常用的包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei']#顯示中文
導入數據并讀取前五行
df = pd.read_csv("鏈家二手房.csv",engine='python')
df.head()
因為中文字符的列名在處理的時候比較麻煩,將其轉化為英文字符的列名,并查看數據顯示前五行
df.rename(columns = {'小區名稱':'village','戶型':'house_type',
'面積':'area','區域':'district','朝向':'orientations','價格(W)':'total_price',
'單價(平方米)':'unit_price','建筑時間':'construction_time','樓層':'floor'},inplace = True)
df.head()
查看數據類型及缺失情況
df.dtypes #查看數據類型
df.isnull().sum() #查看數據缺失情況
- orientations字段缺失行數為1355,construction_time字段缺失行數為6216,floor字段缺失行數為755,這些缺失值在下面對其進行分析時再加以處理
由上面數據預覽可知,應將floor列分成兩列以便后續分析使用,故在此將其分成兩列并查看前五行數據
df1 = pd.concat([df,df['floor'].str.split('/',expand = True)],axis = 1)
df1.head()
- split是分隔符;concat兩表的聯結,axis = 1按列維度合并
刪除floor列,重命名新得到的列
del df1['floor']
df1.rename(columns = {0:'floor_level',1:'floor'},inplace = True)
df1.tail()
數據清洗:提取construction_time和floor字段中的數字、刪除文字部分,查看前5行數據
df1['construction_time']=df1['construction_time'].str.extract('(\d+)年建')
df1['floor']=df1['floor'].str.extract('(\d+)層')
df1.head()
查看數據類型
df1.info()
- construction_time和floor是字符串的格式,轉化為浮點數的格式
df1['construction_time'] = df1['construction_time'].astype(float)
df1['floor'] = df1['floor'].astype(float)
df1.dtypes
查看描述性統計
df1.describe() #查看描述性統計
- 由以上描述性統計結果可以得到如下信息:
- 1.面積平均值為96㎡,面積中位數為85㎡,說明少數大面積的房源拉高了的總體平均水平
- 2.總價平均值為580萬,總價中位數為430萬,情況與上面一樣,少數總價高的房源拉高了總體的平均水平
- 3.單價平均數為59725元,單價中位數為58068元,平均值與中位數基本相等,說明房價升高趨勢比較線性
2、數據分析:各城區房源數量分布
【找一張上海地區結構圖】
上海市區共分為三個等級:
1、黃浦區、長寧區;
2、靜安區、徐匯區;
3、楊浦區、虹口區、普陀區。
上海郊區共分為三個等級:
1、寶山區、閔行區;
2、松江區、嘉定區、青浦區;
3、奉賢區、崇明區、金山區。
district_number=df1.district.value_counts().reset_index().sort_values(by='district',ascending=False)
district_number
可視化
plt.figure(figsize=(9,4))
district_number.plot(x = 'index',y = 'district',kind = 'line')
plt.title('各城區房源數量')
- 由以上柱狀圖分析可知,除了靜安區、金山區和崇明區房源數量不到50以外,其他14個城區二手房數量均在1300套以上,數量最多的為浦東區,共有2599套
3、各城區總面積和平均面積的分布
3.1各城區總面積分布
因為靜安、金山、崇明區的房源較少無法代表整體,所以在這里刪除這三個區的數據
dis_list=list(df1.district.drop_duplicates())#drop_duplicates()去除確定列下的重復列
#drop_duplicates()去除確定列下的重復列
dis_list.remove('崇明')
dis_list.remove('金山')
dis_list.remove('靜安')
dis_list
刪除上述的三個區,并查看刪除后的所有數據前五行
df2 = df1[df1.district.isin(dis_list)]
df2.head()
計算各城區二手房源總面積:
grouped_total_area = df2.groupby('district').sum().sort_values('area',ascending = False).reset_index()
grouped_total_area
可視化:作出各城區總面積折線圖
plt.figure(figsize=(12,5))
grouped_total_area.plot(x = 'district',y = 'area',kind = 'line')
plt.title('各城區總面積分布')
- 由上圖可知,總面積排名前三位的分別是:青浦、松江和浦東,這得益于它們較大的面積
3.2各城區平均面積分布
grouped_area = df2.groupby('district').area.mean().reset_index().sort_values('area',ascending = False)
grouped_area
可視化:作出各城區平均面積折線圖
plt.figure(figsize = (9,5))
plt.plot(grouped_area.district,grouped_area.area)
plt.title('各城區平均面積分布')
- 以上折線圖顯示,青浦區總面積和平均面積遠遠大于其他城區平均面積,青浦區共有房源1769套,數量較大,不太可能出現異常,故分析可能原因為:不在中心位置,建設成本較低,房屋設計面積較大。
- 各城區總面積和平均面積趨勢大致一樣,各城區平均面積在[77,116]之間,其中,面積在[100,116]之間的為松江、黃埔和金山,面積在[90,100)之間的為奉賢、長寧、閔行和靜安,面積在[80,90)之間的為嘉定、虹口、崇明、浦東、閘北、寶山、普陀和徐匯,楊浦區平均面積為77.8㎡。
3.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'
df2.head()
求出各戶型的數量:
grouped_area_level=df2.groupby('area_level').total_price.count().reset_index()
grouped_area_level
可視化:作出各戶型數量柱狀圖
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]㎡
4、數據分析:各城區總價和單價分布
4.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('各城區總價箱線圖')
各城區總價平均值排名:
total_price_mean = df2.groupby('district')['total_price'].mean().reset_index().sort_values('total_price')
total_price_mean
- 由以上結果可知
- 總價No.1的為黃浦區,平均值為1059.3萬,總價區間跨越大,總體價格價格區間為[500,1300]萬,中位數小于平均值,故少數價格高的拉高總體平均值的現象比較嚴重
- 總價No.2的為長寧區,平均值為760.8萬,總體價格區間為[400,1000]萬,中位數接近平均值,總價上升比較線性
- 總價No.3的為徐匯區,平均值為671.8萬,總體價格區間為[400,800]萬,中位數小于平均值,故少數價格高的拉高了總體平均值
- 總價No.4的為青浦區,平均值為676.0萬,總價價格區間為[300,750]萬,中位數遠小于平均值,故少數價格高的拉高總體平均值的現象比較嚴重
4.2、平均總價分布
df2.total_price.hist(bins = 20)
plt.title('平均總價分布圖')
- 房屋總價是一個左凸的直方圖,90%的數據集中在[500,1000]的區間,即90%的房源總價在500萬到1000萬之間,只有大概10%的房源屬于極高的價格,這個結果符合現實的房價分布
4.3、各城區單價分布
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('各城區單價分布箱線圖')
各城區單價排名:
unit_price_mean = df2.groupby('district')['district','unit_price'].mean().reset_index().sort_values('unit_price',ascending = False)
unit_price_mean
- 由以上結果可知,
- 單價No.1的是黃浦,平均值為90666元,大體價格區間為[78000,100000]元
- 單價No.2的是徐匯,平均值為79157元,大體價格區間為[69111,90000]元
- 單價No.3的是長寧,平均值為75081元,大體價格區間為[66000,84000]元
全市單價分布:
df2.unit_price.hist(bins = 20)
plt.title('全市單價分布直方圖')
- 單價直方圖接近正態分布,該圖顯示70%的單價集中在區間[30000,90000]元,符合房價的現實分布規律
4.4、總價和單價排名前十小區
對小區進行分組,計算出各小區房源數量,并按照房源數量降序的順序排序
df3 = df2.groupby('village').total_price.count().reset_index().sort_values('total_price',ascending = False)
df3.head()
- 因為很多小區房源數量太少,其統計值不具有代表性,故在此過濾掉房源數量小于20的小區
df4 = df3[df3.total_price > 20]
df4.head()
提取房源數大于20的全部數據
df5 = df2[df2.village.isin(df4.village)]
df5.head()
4.5、計算各小區總價排名前15的小區:
對小區進行分組,計算出各小區房源數量,并按照房源數量降序的順序排序
df3 = df2.groupby('village').total_price.count().reset_index().sort_values('total_price',ascending = False)
df3.head(20)
因為很多小區房源數量太少,其統計值不具有代表性,故在此過濾掉房源數量小于20的小區
# 過濾掉房源小于20的小區
df4 = df3[df3.total_price > 20]
df4.head(10)
提取房源數量大于20的小區的全部數據
df5 = df2[df2.village.isin(df4.village)]
df5.head()
計算各小區總價排名前15的小區:
totalp_village = df5.groupby('village').total_price.mean().sort_values(ascending = False).reset_index().head(15)
totalp_village
可視化:作出平均總價排名前十小區的平均總價柱狀圖
plt.figure(figsize=(20,4))
plt.bar(totalp_village.village,totalp_village.total_price)
plt.title('平均總價排名前15的小區')
- 總價排名前15的小區如上圖所示,第一名為翠湖天地御苑,平均總價超過4000萬,是第二名尚海灣豪庭的兩倍,查詢了解到,該小區位于上海市的心臟地帶,真可謂寸土寸金
4.6、計算單價排名前十五的小區
totalp_village1=df5.groupby('village').unit_price.mean().sort_values(ascending=False).head(15).reset_index()
totalp_village1
可視化:作出平均單價排名前十小區的單價柱狀圖
plt.figure(figsize = (20,5))
plt.bar(totalp_village1.village,totalp_village1.unit_price)
plt.title('平均單價排名前15小區')
- 由上圖可知,排名前三位的小區分別是翠湖天地御苑、東方曼哈頓和融創濱江壹號院,翠湖天地御苑的平均單價最高,超過了150000元,高于排名第二的東方曼哈頓近40000元
5、房價與戶型、樓層、朝向、建筑年代的關系
5.1、房價與戶型的關系
按戶型進行分組,計算出每個戶型的房源數量,過濾掉房源數量小于100的戶型
grouped_house_type = df2.groupby('house_type').total_price.count().sort_values(ascending = False).reset_index()
grouped_house_type2 = grouped_house_type.loc[grouped_house_type.total_price> 100]
grouped_house_type2
可視化:作出各戶型的數量柱狀圖
plt.figure(figsize = (10,5))
plt.bar(grouped_house_type2.house_type,grouped_house_type2.total_price)
plt.title('各戶型數量柱狀圖')
戶型與房屋均價的柱狀圖
grouped_house_type3 = df6.groupby('house_type').unit_price.mean().sort_values(ascending = False).reset_index()
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廳。可以看出,小戶型的房屋比較受歡迎,因為其總價一般較低,經濟壓力較小,故而成為熱門戶型,這也導致了這些戶型價格的上漲,使得小戶型的房屋單價高于大戶型的房屋。
5.2、房價與樓層的關系
計算各個樓層等級的房源數量,注意這里是按照地區高中中區劃分的,并不是按照floor劃分的
a_list=['高區','中區','低區']
df7 = df2[df2.floor_level.isin(a_list)]
grouped_floor_level = df7.groupby('floor_level').unit_price.count().reset_index()
grouped_floor_level.head()
可視化:并作出其柱狀圖
plt.title('樓層等級-數量')
plt.bar(grouped_floor_level.floor_level,grouped_floor_level.unit_price)
- 由上圖可知,低、中、高區的房源數量基本相等,都在8000套以上,其中高區最多,數量超過10000套
計算各樓層等級的平均單價平均總價
平均單價
grouped_floor_level1 = df7.groupby('floor_level').unit_price.mean().reset_index()
grouped_floor_level1
可視化:作出其柱狀圖
plt.title('樓層等級—平均單價')
plt.bar(grouped_floor_level1.floor_level,grouped_floor_level1.unit_price)
由上圖可知,低、中、高區樓層平均單價在6萬元附近
平均總價
grouped_floor_level2 = df7.groupby('floor_level').total_price.mean().reset_index()
grouped_floor_level2
可視化:柱狀圖
plt.title('樓層等級—平均總價')
plt.bar(grouped_floor_level2.floor_level,grouped_floor_level2.total_price)
由上圖可知,低、中、高區樓層平均總價均超過500萬,其中低區總價最高,為590萬
查看缺失值
df2.isnull().sum()
缺失值的處理
# 填充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字段中空值所在的行已被全部刪除
計算樓層平均單價排名前15位
df2.groupby('floor').unit_price.mean().sort_values(ascending = False).reset_index().head(15)
計算各樓層單價平均值,并作出其折線圖:
plt.figure(figsize=(15,5))
df2.groupby('floor').unit_price.mean().plot()
plt.title('樓層數-單價')
- 由上圖分析可知,隨著樓層輸的增加,房價也隨之升高。在37層之前,房價隨樓層數增加而增加的趨勢比較線性,但是在這之后房價隨樓層數增加而增加的趨勢波動很大,可能的原因是樓層數超過40的住宅數量較小,超過40層的數據量比較小,容易產生誤差
5.3、房價與朝向的關系
查看房屋的朝向
df2.orientations.drop_duplicates().values.tolist()
朝向重新構成一個列表
b_list=list(['朝東','朝東北','朝東南','朝東西','朝北','朝南','朝南北','朝西','朝西北','朝西南'])
df8 = df2[df2.orientations.isin(b_list)]
grouped_orientations = df8.groupby('orientations').unit_price.mean().sort_values(ascending = False).reset_index()
grouped_orientations
可視化:作出其柱狀圖
plt.figure(figsize=(12,5))
plt.bar(grouped_orientations.orientations,grouped_orientations.unit_price)
plt.title('朝向—單價')
- 由上圖可知,朝向對房價有一定的影響,朝向南面(南、東南、西南)的房子總體價格會高一點。這一現象也符合生活情景,朝向南面的房屋采光會比較好,這些南北通透的房子單價相對于其他朝向會高一些。
5.4、房價與建筑年代的關系
缺失值的處理
# 填充construction_time字段中的空值為000
df2.construction_time=df2.construction_time.fillna('000')
# 找出construction_time字段中值為123的行號
d_list=df2[df2.construction_time=='000'].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年以來修建的房屋呈現陡然上升的趨勢,這也和目前房價不斷升高的趨勢契合,這表明房價在短時間內不會出現大的下跌,是否會出現下一個房價高峰,我們拭目以待。