來自:Python資料科學(微訊號:Python_Spiderman)
北京二手房房價分析與預測
目的:本篇給大家介紹一個資料分析的初級專案,目的是透過專案瞭解如何使用Python進行簡單的資料分析。
資料源:博主透過爬蟲採集的鏈家全網北京二手房資料(後臺回覆 0022 便可獲取)。
首先匯入要使用的科學計算包numpy
,pandas
,視覺化matplotlib
,seaborn
,以及機器學習包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 來完成此專案')
然後匯入資料,併進行初步的觀察,這些觀察包括瞭解資料特徵的缺失值,異常值,以及大概的描述性統計。
# 匯入鏈家二手房資料
lianjia_df = pd.read_csv('lianjia.csv')
display(lianjia_df.head(n=2))
初步觀察到一共有11個特徵變數,Price 在這裡是我們的標的變數,然後我們繼續深入觀察一下。
# 檢查缺失值情況
lianjia_df.info()
發現了資料集一共有條資料,其中 23677
特徵有明顯的缺失值。 Elevator
lianjia_df.describe()
上面結果給出了特徵值是數值的一些統計值,包括平均數,標準差,中位數,最小值,最大值,25%分位數,75%分位數。這些統計結果簡單直接,對於初始瞭解一個特徵好壞非常有用,比如我們觀察到 Size 特徵 的最大值為1019平米,最小值為2平米,那麼我們就要思考這個在實際中是不是存在的,如果不存在沒有意義,那麼這個資料就是一個異常值,會嚴重影響模型的效能。
當然,這隻是初步觀察,後續我們會用資料視覺化來清晰的展示,並證實我們的猜測。
# 新增新特徵房屋均價
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)
# 重新審視資料集
display(df.head(n=2))
我們發現 Id 特徵其實沒有什麼實際意義,所以將其移除。由於房屋單價分析起來比較方便,簡單的使用總價/面積就可得到,所以增加一個新的特徵 PerPrice(只用於分析,不是預測特徵)。另外,特徵的順序也被調整了一下,看起來比較舒服。
Region特徵分析
對於區域特徵,我們可以分析不同區域房價和數量的對比。
# 對二手房區域分組對比二手房數量和每平米房價
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('北京各大區二手房每平米單價對比',fontsize=15)
ax1.set_xlabel('區域')
ax1.set_ylabel('每平米單價')
sns.barplot(x='Region', y='Price', palette="Greens_d", data=df_house_count, ax=ax2)
ax2.set_title('北京各大區二手房數量對比',fontsize=15)
ax2.set_xlabel('區域')
ax2.set_ylabel('數量')
sns.boxplot(x='Region', y='Price', data=df, ax=ax3)
ax3.set_title('北京各大區二手房房屋總價',fontsize=15)
ax3.set_xlabel('區域')
ax3.set_ylabel('房屋總價')
plt.show()
-
二手房均價:西城區的房價最貴均價大約11萬/平,因為西城在二環以裡,且是熱門學區房的聚集地。其次是東城大約10萬/平,然後是海澱大約8.5萬/平,其它均低於8萬/平。
-
二手房房數量:從數量統計上來看,目前二手房市場上比較火熱的區域。海澱區和朝陽區二手房數量最多,差不多都接近3000套,畢竟大區,需求量也大。然後是豐臺區,近幾年正在改造建設,有趕超之勢。
-
二手房總價:透過箱型圖看到,各大區域房屋總價中位數都都在1000萬以下,且房屋總價離散值較高,西城最高達到了6000萬,說明房屋價格特徵不是理想的正太分佈。
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)
# 建房時間和出售價格的關係
sns.regplot(x='Size', y='Price', data=df, ax=ax2)
plt.show()
-
Size 分佈:
透過 distplot 和 kdeplot 繪製柱狀圖觀察 Size 特徵的分佈情況,屬於長尾型別的分佈,這說明瞭有很多面積很大且超出正常範圍的二手房。
-
Size 與 Price 的關係:
透過 regplot 繪製了 Size 和 Price 之間的散點圖,發現 Size 特徵基本與Price呈現線性關係,符合基本常識,面積越大,價格越高。但是有兩組明顯的異常點:1. 面積不到10平米,但是價格超出10000萬;2. 一個點面積超過了1000平米,價格很低,需要檢視是什麼情況。
df.loc[df['Size']< 10]
經過檢視發現這組資料是別墅,出現異常的原因是由於別墅結構比較特殊(無朝向無電梯),欄位定義與二手商品房不太一樣導致爬蟲爬取資料錯位。也因別墅型別二手房不在我們的考慮範圍之內,故將其移除再次觀察Size分佈和Price關係。
df.loc[df['Size']>1000]
經觀察這個異常點不是普通的民用二手房,很可能是商用房,所以才有1房間0廳確有如此大超過1000平米的面積,這裡選擇移除。
df = df[(df['Layout']!='疊拼別墅')&(df['Size']<1000)]
重新進行視覺化發現就沒有明顯的異常點了。
f, ax1= plt.subplots(figsize=(20,20))
sns.countplot(y='Layout', data=df, ax=ax1)
ax1.set_title('房屋戶型',fontsize=15)
ax1.set_xlabel('數量')
ax1.set_ylabel('戶型')
plt.show()
這個特徵真是不看不知道,各種廳室組合搭配,竟然還有9室3廳,4室0廳等奇怪的結構。其中,2室一廳佔絕大部分,其次是3室一廳,2室2廳,3室兩廳。但是仔細觀察特徵分類下有很多不規則的命名,比如2室一廳與2房間1衛,還有別墅,沒有統一的叫法。這樣的特徵肯定是不能作為機器學習模型的資料輸入的,需要使用特徵工程進行相應的處理。
df['Renovation'].value_counts()
精裝 11345簡裝 8497其他 3239毛坯 576
南北 20
Name: Renovation, dtype: int64
# 去掉錯誤資料“南北”,因為爬蟲過程中一些資訊位置為空,導致“Direction”的特徵出現在這裡,需要清除或替換
df['Renovation'] = df.loc[(df['Renovation'] != '南北'), 'Renovation']
# 畫幅設定
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()
misn = len(df.loc[(df['Elevator'].isnull()), 'Elevator'])
print('Elevator缺失值數量為:'+ str(misn))
Elevator 缺失值數量為:8237
這麼多的缺失值怎麼辦呢?這個需要根據實際情況考慮,常用的方法有平均值/中位數填補法,直接移除,或者根據其他特徵建模預測等。
這裡我們考慮填補法,但是有無電梯不是數值,不存在平均值和中位數,怎麼填補呢?這裡給大家提供一種思路:就是根據樓層 Floor 來判斷有無電梯,一般的樓層大於6的都有電梯,而小於等於6層的一般都沒有電梯。有了這個標準,那麼剩下的就簡單了。
# 由於存在個別型別錯誤,如簡裝和精裝,特徵值錯位,故需要移除
df['Elevator'] = df.loc[(df['Elevator'] == '有電梯')|(df['Elevator'] == '無電梯'), 'Elevator']
# 填補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('有無電梯數量對比',fontsize=15)
ax1.set_xlabel('是否有電梯')
ax1.set_ylabel('數量')
sns.barplot(x='Elevator', y='Price', data=df, ax=ax2)
ax2.set_title('有無電梯房價對比',fontsize=15)
ax2.set_xlabel('是否有電梯')
ax2.set_ylabel('總價')
plt.show()
grid = sns.FacetGrid(df, row='Elevator', col='Renovation', palette='seismic',size=4)
grid.map(plt.scatter, 'Year', 'Price')
grid.add_legend()
-
整個二手房房價趨勢是隨著時間增長而增長的;
-
2000年以後建造的二手房房價相較於2000年以前有很明顯的價格上漲;
-
1980年之前幾乎不存在有電梯二手房資料,說明1980年之前還沒有大面積安裝電梯;
-
1980年之前無電梯二手房中,簡裝二手房佔絕大多數,精裝反而很少;
f, ax1= plt.subplots(figsize=(20,5))
sns.countplot(x='Floor', data=df, ax=ax1)
ax1.set_title('房屋戶型',fontsize=15)
ax1.set_xlabel('數量')
ax1.set_ylabel('戶型')
plt.show()
本次分享旨在讓大家瞭解如何用Python做一個簡單的資料分析,對於剛剛接觸資料分析的朋友無疑是一個很好的練習。不過,這個分析還存在很多問題需要解決,比如:
-
解決爬蟲獲取的資料源準確度問題;
-
需要爬取或者尋找更多好的售房特徵;
-
需要做更多地特徵工程工作,比如資料清洗,特徵選擇和篩選;
-
使用統計模型建立回歸模型進行價格預測;
●編號509,輸入編號直達本文
●輸入m獲取到文章目錄
Java程式設計
更多推薦《18個技術類公眾微信》
涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。