用Python分析北京二手房房價
數(shù)據(jù)初探
首先導(dǎo)入要使用的科學(xué)計(jì)算包numpy,pandas,可視化matplotlib,seaborn,以及機(jī)器學(xué)習(xí)包sklearn。
- import pandas as pd
- import numpy as np
- import seaborn as sns
- import matplotlib as mpl
- import matplotlib.pyplot as plt
- from IPython.display import display
- plt.style.use("fivethirtyeight")
- sns.set_style({'font.sans-serif':['simhei','Arial']})
- %matplotlib inline
- # 檢查Python版本
- from sys import version_info
- if version_info.major != 3:
- raise Exception('請使用Python 3 來完成此項(xiàng)目')
然后導(dǎo)入數(shù)據(jù),并進(jìn)行初步的觀察,這些觀察包括了解數(shù)據(jù)特征的缺失值,異常值,以及大概的描述性統(tǒng)計(jì)。
- # 導(dǎo)入鏈家二手房數(shù)據(jù)
- lianjia_df = pd.read_csv('lianjia.csv')
- display(lianjia_df.head(n=2))
初步觀察到一共有11個特征變量,Price 在這里是我們的目標(biāo)變量,然后我們繼續(xù)深入觀察一下。
- # 檢查缺失值情況
- lianjia_df.info()
發(fā)現(xiàn)了數(shù)據(jù)集一共有23677條數(shù)據(jù),其中Elevator特征有明顯的缺失值。
- lianjia_df.describe()
上面結(jié)果給出了特征值是數(shù)值的一些統(tǒng)計(jì)值,包括平均數(shù),標(biāo)準(zhǔn)差,中位數(shù),最小值,最大值,25%分位數(shù),75%分位數(shù)。這些統(tǒng)計(jì)結(jié)果簡單直接,對于初始了解一個特征好壞非常有用,比如我們觀察到 Size 特征 的最大值為1019平米,最小值為2平米,那么我們就要思考這個在實(shí)際中是不是存在的,如果不存在沒有意義,那么這個數(shù)據(jù)就是一個異常值,會嚴(yán)重影響模型的性能。
當(dāng)然,這只是初步觀察,后續(xù)我們會用數(shù)據(jù)可視化來清晰的展示,并證實(shí)我們的猜測。
- # 添加新特征房屋均價
- df = lianjia_df.copy()
- df['PerPrice'] = lianjia_df['Price']/lianjia_df['Size']
- # 重新擺放列位置
- columns = ['Region', 'District', 'Garden', 'Layout', 'Floor', 'Year', 'Size', 'Elevator', 'Direction', 'Renovation', 'PerPrice', 'Price']
- df = pd.DataFrame(df, columns = columns)
- # 重新審視數(shù)據(jù)集
- display(df.head(n=2)
我們發(fā)現(xiàn) Id 特征其實(shí)沒有什么實(shí)際意義,所以將其移除。由于房屋單價分析起來比較方便,簡單的使用總價/面積就可得到,所以增加一個新的特征 PerPrice(只用于分析,不是預(yù)測特征)。另外,特征的順序也被調(diào)整了一下,看起來比較舒服。
數(shù)據(jù)可視化分析
Region特征分析
對于區(qū)域特征,我們可以分析不同區(qū)域房價和數(shù)量的對比。
- # 對二手房區(qū)域分組對比二手房數(shù)量和每平米房價
- df_house_count = df.groupby('Region')['Price'].count().sort_values(ascending=False).to_frame().reset_index()
- df_house_mean = df.groupby('Region')['PerPrice'].mean().sort_values(ascending=False).to_frame().reset_index()
- f, [ax1,ax2,ax3] = plt.subplots(3,1,figsize=(20,15))
- sns.barplot(x='Region', y='PerPrice', palette="Blues_d", data=df_house_mean, ax=ax1)
- ax1.set_title('北京各大區(qū)二手房每平米單價對比',fontsize=15)
- ax1.set_xlabel('區(qū)域')
- ax1.set_ylabel('每平米單價')
- sns.barplot(x='Region', y='Price', palette="Greens_d", data=df_house_count, ax=ax2)
- ax2.set_title('北京各大區(qū)二手房數(shù)量對比',fontsize=15)
- ax2.set_xlabel('區(qū)域')
- ax2.set_ylabel('數(shù)量')
- sns.boxplot(x='Region', y='Price', data=df, ax=ax3)
- ax3.set_title('北京各大區(qū)二手房房屋總價',fontsize=15)
- ax3.set_xlabel('區(qū)域')
- ax3.set_ylabel('房屋總價')
- plt.show()
使用了pandas的網(wǎng)絡(luò)透視功能 groupby 分組排序。區(qū)域特征可視化直接采用 seaborn 完成,顏色使用調(diào)色板 palette 參數(shù),顏色漸變,越淺說明越少,反之越多??梢杂^察到:
- 二手房均價:西城區(qū)的房價最貴均價大約11萬/平,因?yàn)槲鞒窃诙h(huán)以里,且是熱門學(xué)區(qū)房的聚集地。其次是東城大約10萬/平,然后是海淀大約8.5萬/平,其它均低于8萬/平。
- 二手房房數(shù)量:從數(shù)量統(tǒng)計(jì)上來看,目前二手房市場上比較火熱的區(qū)域。海淀區(qū)和朝陽區(qū)二手房數(shù)量最多,差不多都接近3000套,畢竟大區(qū),需求量也大。然后是豐臺區(qū),近幾年正在改造建設(shè),有趕超之勢。
- 二手房總價:通過箱型圖看到,各大區(qū)域房屋總價中位數(shù)都都在1000萬以下,且房屋總價離散值較高,西城最高達(dá)到了6000萬,說明房屋價格特征不是理想的正太分布。
Size特征分析
- f, [ax1,ax2] = plt.subplots(1, 2, figsize=(15, 5))
- # 建房時間的分布情況
- sns.distplot(df['Size'], bins=20, ax=ax1, color='r')
- sns.kdeplot(df['Size'], shade=True, ax=ax1)
- # 建房時間和出售價格的關(guān)系
- sns.regplot(x='Size', y='Price', data=df, ax=ax2)
- plt.show()
Size 分布:
- 通過 distplot 和 kdeplot 繪制柱狀圖觀察 Size 特征的分布情況,屬于長尾類型的分布,這說明了有很多面積很大且超出正常范圍的二手房。
Size 與 Price 的關(guān)系:
- 通過 regplot 繪制了 Size 和 Price 之間的散點(diǎn)圖,發(fā)現(xiàn) Size 特征基本與Price呈現(xiàn)線性關(guān)系,符合基本常識,面積越大,價格越高。但是有兩組明顯的異常點(diǎn):1. 面積不到10平米,但是價格超出10000萬;2. 一個點(diǎn)面積超過了1000平米,價格很低,需要查看是什么情況。
- df.loc[df['Size']< 10]
經(jīng)過查看發(fā)現(xiàn)這組數(shù)據(jù)是別墅,出現(xiàn)異常的原因是由于別墅結(jié)構(gòu)比較特殊(無朝向無電梯),字段定義與二手商品房不太一樣導(dǎo)致爬蟲爬取數(shù)據(jù)錯位。也因別墅類型二手房不在我們的考慮范圍之內(nèi),故將其移除再次觀察Size分布和Price關(guān)系。
df.loc[df['Size']>1000]
經(jīng)觀察這個異常點(diǎn)不是普通的民用二手房,很可能是商用房,所以才有1房間0廳確有如此大超過1000平米的面積,這里選擇移除。
- df.loc[df['Size']>1000]
重新進(jìn)行可視化發(fā)現(xiàn)就沒有明顯的異常點(diǎn)了。
Layout特征分析
- f, ax1= plt.subplots(figsize=(20,20))
- sns.countplot(y='Layout', data=df, ax=ax1)
- ax1.set_title('房屋戶型',fontsize=15)
- ax1.set_xlabel('數(shù)量')
- ax1.set_ylabel('戶型')
- plt.show()
這個特征真是不看不知道,各種廳室組合搭配,竟然還有9室3廳,4室0廳等奇怪的結(jié)構(gòu)。其中,2室一廳占絕大部分,其次是3室一廳,2室2廳,3室兩廳。但是仔細(xì)觀察特征分類下有很多不規(guī)則的命名,比如2室一廳與2房間1衛(wèi),還有別墅,沒有統(tǒng)一的叫法。這樣的特征肯定是不能作為機(jī)器學(xué)習(xí)模型的數(shù)據(jù)輸入的,需要使用特征工程進(jìn)行相應(yīng)的處理。
Renovation 特征分析
- df['Renovation'].value_counts()
- 精裝 11345
- 簡裝 8497
- 其他 3239
- 毛坯 576南北 20
- Name: Renovation, dtype: int64
發(fā)現(xiàn)Renovation裝修特征中竟然有南北,它屬于朝向的類型,可能是因?yàn)榕老x過程中一些信息位置為空,導(dǎo)致“Direction”朝向特征出現(xiàn)在這里,所以需要清除或替換掉。
- # 去掉錯誤數(shù)據(jù)“南北”,因?yàn)榕老x過程中一些信息位置為空,導(dǎo)致“Direction”的特征出現(xiàn)在這里,需要清除或替換
- df['Renovation'] = df.loc[(df['Renovation'] != '南北'), 'Renovation']
- # 畫幅設(shè)置
- f, [ax1,ax2,ax3] = plt.subplots(1, 3, figsize=(20, 5))
- sns.countplot(df['Renovation'], ax=ax1)
- sns.barplot(x='Renovation', y='Price', data=df, ax=ax2)
- sns.boxplot(x='Renovation', y='Price', data=df, ax=ax3)
- plt.show()
觀察到,精裝修的二手房數(shù)量最多,簡裝其次,也是我們平日常見的。而對于價格來說,毛坯類型卻是最高,其次是精裝修。
Elevator 特征分析
初探數(shù)據(jù)的時候,我們發(fā)現(xiàn) Elevator 特征是有大量缺失值的,這對于我們是十分不利的,首先我們先看看有多少缺失值:
- misn = len(df.loc[(df['Elevator'].isnull()), 'Elevator'])
- print('Elevator缺失值數(shù)量為:'+ str(misn))
Elevator 缺失值數(shù)量為:8237
這么多的缺失值怎么辦呢?這個需要根據(jù)實(shí)際情況考慮,常用的方法有平均值/中位數(shù)填補(bǔ)法,直接移除,或者根據(jù)其他特征建模預(yù)測等。
這里我們考慮填補(bǔ)法,但是有無電梯不是數(shù)值,不存在平均值和中位數(shù),怎么填補(bǔ)呢?這里給大家提供一種思路:就是根據(jù)樓層 Floor 來判斷有無電梯,一般的樓層大于6的都有電梯,而小于等于6層的一般都沒有電梯。有了這個標(biāo)準(zhǔn),那么剩下的就簡單了。
- # 由于存在個別類型錯誤,如簡裝和精裝,特征值錯位,故需要移除
- df['Elevator'] = df.loc[(df['Elevator'] == '有電梯')|(df['Elevator'] == '無電梯'), 'Elevator']
- # 填補(bǔ)Elevator缺失值
- df.loc[(df['Floor']>6)&(df['Elevator'].isnull()), 'Elevator'] = '有電梯'
- df.loc[(df['Floor']<=6)&(df['Elevator'].isnull()), 'Elevator'] = '無電梯'
- f, [ax1,ax2] = plt.subplots(1, 2, figsize=(20, 10))
- sns.countplot(df['Elevator'], ax=ax1)
- ax1.set_title('有無電梯數(shù)量對比',fontsize=15)
- ax1.set_xlabel('是否有電梯')
- ax1.set_ylabel('數(shù)量')
- sns.barplot(x='Elevator', y='Price', data=df, ax=ax2)
- ax2.set_title('有無電梯房價對比',fontsize=15)
- ax2.set_xlabel('是否有電梯')
- ax2.set_ylabel('總價')
- plt.show()
結(jié)果觀察到,有電梯的二手房數(shù)量居多一些,畢竟高層土地利用率比較高,適合北京龐大的人群需要,而高層就需要電梯。相應(yīng)的,有電梯二手房房價較高,因?yàn)殡娞萸捌谘b修費(fèi)和后期維護(hù)費(fèi)包含內(nèi)了(但這個價格比較只是一個平均的概念,比如無電梯的6層豪華小區(qū)當(dāng)然價格更高了)。
Year 特征分析
- grid = sns.FacetGrid(df, row='Elevator', col='Renovation', palette='seismic',size=4)
- grid.map(plt.scatter, 'Year', 'Price')
- grid.add_legend()
在Renovation和Elevator的分類條件下,使用 FaceGrid 分析 Year 特征,觀察結(jié)果如下:
整個二手房房價趨勢是隨著時間增長而增長的;
- 2000年以后建造的二手房房價相較于2000年以前有很明顯的價格上漲;
- 1980年之前幾乎不存在有電梯二手房數(shù)據(jù),說明1980年之前還沒有大面積安裝電梯;
- 1980年之前無電梯二手房中,簡裝二手房占絕大多數(shù),精裝反而很少;
Floor 特征分析
- f, ax1= plt.subplots(figsize=(20,5))
- sns.countplot(x='Floor', data=df, ax=ax1)
- ax1.set_title('房屋戶型',fontsize=15)
- ax1.set_xlabel('數(shù)量')
- ax1.set_ylabel('戶型')
- plt.show()
可以看到,6層二手房數(shù)量最多,但是單獨(dú)的樓層特征沒有什么意義,因?yàn)槊總€小區(qū)住房的總樓層數(shù)都不一樣,我們需要知道樓層的相對意義。另外,樓層與文化也有很重要聯(lián)系,比如中國文化七上八下,七層可能受歡迎,房價也貴,而一般也不會有4層或18層。當(dāng)然,正常情況下中間樓層是比較受歡迎的,價格也高,底層和頂層受歡迎度較低,價格也相對較低。所以樓層是一個非常復(fù)雜的特征,對房價影響也比較大。
總結(jié)
本次分享旨在讓大家了解如何用Python做一個簡單的數(shù)據(jù)分析,對于剛剛接觸數(shù)據(jù)分析的朋友無疑是一個很好的練習(xí)。不過,這個分析還存在很多問題需要解決,比如:
- 解決爬蟲獲取的數(shù)據(jù)源準(zhǔn)確度問題;
- 需要爬取或者尋找更多好的售房特征;
- 需要做更多地特征工程工作,比如數(shù)據(jù)清洗,特征選擇和篩選;
- 使用統(tǒng)計(jì)模型建立回歸模型進(jìn)行價格預(yù)測;
作者:xiaoyu,一個半路轉(zhuǎn)行的數(shù)據(jù)挖掘工程師,Python數(shù)據(jù)科學(xué)。