首先我們要對數(shù)據(jù)進行分析,,可分為以下幾個主要步驟:
- 導入數(shù)據(jù)
- 檢查缺失值情況并對表格進行簡單處理
- 數(shù)據(jù)可視化分析
這里我們重點要講的是數(shù)據(jù)可視化分析,,即對一些重要對特征逐個畫圖觀察。
打開表格:
我們看到上述數(shù)據(jù)有 11 個特征變量,,1 個目標變量 Price,。11 個特征分別為: Direction District Elevator Floor Garden Id Layout Region Renovation Size Year
我們分別對 Elevator, Floor, Layout, Region, Renovation, Size, Year 這 7 個特征進行可視化分析。
Elevator 特征分析
代碼:
# Elevator 特征分析
miss_value = len(df.loc[(df['Elevator'].isnull()), 'Elevator'])
print('Elevator缺失值個數(shù)為:' + str(miss_value))
# 移除表格中可能存在的錯誤的值
df['Elevator'] = df.loc[(df['Elevator']=='有電梯') | (df['Elevator']=='無電梯'), 'Elevator']
# 以樓層大于6的有電梯,,小于等于6層沒有電梯為標準,,填補缺失值
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ù)量對比')
ax1.set_xlabel('是否有電梯')
ax1.set_ylabel('數(shù)量')
sns.barplot(x='Elevator', y='Price', data=df, ax=ax2)
ax2.set_title('有無電梯價格對比')
ax2.set_xlabel('是否有電梯')
ax2.set_ylabel('價格')
plt.show()
執(zhí)行結(jié)果:
分析目的: 分析有無電梯兩種二手房對數(shù)量和價格。
使用方法: 采用seaborn 完成可視化,。
觀察結(jié)果: 我們發(fā)現(xiàn) Elevator 特征是有大量缺失值,。一般有大量缺失值時,需要根據(jù)實際情況考慮,。常用的方法有平均值/中位數(shù)填補法,,直接移除,,或根據(jù)其他特征建模預測等。
這里我們用填補法,。由于有無電梯不是數(shù)值,,不存在平均值和中位數(shù),這里根據(jù)樓層 (Floor) 斷有無電梯,,一般的樓層大于 6 的都有電梯,,而小于等于 6 層的一般都沒有電梯。
在填補缺失值后繼續(xù)觀察,,有電梯的二手房數(shù)量更多,,且房價較高。
Floor 特征分析
代碼:
# Floor 特征分析
f, ax1 = plt.subplots(figsize=(20,5))
sns.countplot(df['Floor'], ax=ax1)
ax1.set_title('各樓層二手房數(shù)量', fontsize=15)
ax1.set_xlabel('樓層')
ax1.set_ylabel('數(shù)量')
plt.show()
執(zhí)行結(jié)果:
分析目的: 分析不同的樓層二手房數(shù)量,。
使用方法: 采用seaborn 完成可視化,。
觀察結(jié)果: 其中 6 層的二手房數(shù)量最多,但是單獨的樓層特征沒有什么意義,,因為每個小區(qū)住房的總樓層數(shù)都不一樣,,我們需要知道樓層的相對高度。
此外,,樓層與文化也有很重要的聯(lián)系,,比如在中國文化有七上八下,七層可能受歡迎等,。一般來說中間樓層比較受歡迎,,價格也高,底層和頂層受歡迎度較低,,價格也相對較低,。
樓層是一個非常復雜的特征,對房價影響也比較大,。
Layout 特征分析
代碼:
# 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()
執(zhí)行結(jié)果:
分析目的: 分析不同戶型的數(shù)量,。
使用方法: 采用seaborn 完成可視化。
觀察結(jié)果: 這個特征分類下有很多不規(guī)則的命名,,以上特征是不能作為機器學習模型的數(shù)據(jù)輸入的,,需要使用特征工程進行相應的處理。
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('北京各區(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()
執(zhí)行結(jié)果:
分析目的: 分析不同區(qū)域的房價和數(shù)量,,并進行對比,。
使用方法: 用pandas 的網(wǎng)絡透視功能groupby 分組排序。 區(qū)域特征可視化采用seaborn 完成,。 顏色使用調(diào)色板palette 參數(shù),,顏色越淺數(shù)量越少,反之越多,。
觀察結(jié)果: 二手房每平方米單價對比:西城區(qū)的房價最貴均價大約 11 萬/平,,因為西城在二環(huán)以里,,且是熱門學區(qū)房的聚集地。其次是東城大約 10 萬/平,,然后是海淀大約 8.5 萬/平,,其它均低于 8 萬/平。
二手房房數(shù)量對比:從數(shù)量統(tǒng)計上來看,,海淀區(qū)和朝陽區(qū)二手房數(shù)量最多,,約接近 3000 套,因為二者屬于大區(qū),。其次是豐臺區(qū),,近幾年正在改造建設,需求量大,。
二手房房屋總價對比:通過箱型圖看到,,各大區(qū)域房屋總價中位數(shù)都都在 1000 萬以下,且房屋總價離散值較高,,西城最高達到了 6000 萬,,說明房屋價格特征并不是理想的正態(tài)分布。
Renovation 特征分析
代碼:
# Renovation 特征分析
df['Renovation'].value_counts()
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()
執(zhí)行結(jié)果:
分析目的: 分析不同裝修程度的二手房數(shù)量和房價,。
使用方法: 采用seaborn 完成可視化,。
觀察結(jié)果: 對于數(shù)量來說,精裝修的二手房最多,,簡裝其次,;對于價格來說,毛坯房價格最高,,其次是精裝修的,。
Size 特征分析
代碼:
# 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'], ax=ax1, shade=True)
# 建房時間和出售價格的關系
sns.regplot(x='Size', y='Price', data=df, ax=ax2)
plt.show()
# 查看異常值
df.loc[df['Size'] < 10]
df.loc[df['Size'] > 1000]
# 移除上述兩種異常值
df = df[(df['Layout']!='疊拼別墅') & (df['Size']<1000)]
# 重新進行可視化發(fā)現(xiàn)就沒有明顯的異常點
sns.regplot(x='Size', y='Price', data=df)
plt.show()
執(zhí)行結(jié)果:
分析目的: 分析不同大小的二手房和價格的關系。
使用方法: 通過distplot 和 kdeplot 繪制柱狀圖觀察 Size 特征的分布情況,,屬于長尾類型的分布,,這說明有很多面積很大且超出正常范圍的二手房。
通過 regplot 繪制了 Size 和 Price 之間的散點圖,,發(fā)現(xiàn) Size 特征基本與Price 呈現(xiàn)線性關系,,符合基本常識,,面積越大,,價格越高。
觀察結(jié)果: 有兩組明顯的異常點:面積不到 10 平米但價格超出 10000 萬和面積超過了 1000 平米價格很低兩種情況,。
經(jīng)過查看發(fā)現(xiàn)這兩組異常值分別是別墅和商用房,,因此出現(xiàn)異常,故將其移除再次觀察Size分布和Price關系,。
這里也說明我們在觀察數(shù)據(jù)的時候,,要緊密結(jié)合實際業(yè)務需求來分析,,才能得出更準確的結(jié)果。
Year 特征分析
代碼:
# Year 特征分析
grid = sns.FacetGrid(df, row='Elevator', col='Renovation', palette='seismic', size=4)
grid.map(plt.scatter, 'Year', 'Price')
# grid.add_legend()
執(zhí)行結(jié)果:
分析目的: 分析不同年代對房價變化的影響,。
使用方法: 在 Renovation 和 Elevator 的分類條件下,,使用 FacetGrid 分析 Year 特征
觀察結(jié)果: 觀察數(shù)據(jù)可視化圖表可以看出,整個二手房房價趨勢是隨著時間增長而增長的,,2000 年以后建造的二手房房價相較于 2000 年以前有很明顯的價格上漲,。此外,1980年之前幾乎不存在有電梯二手房數(shù)據(jù),,說明1980年之前還沒有大面積安裝電梯,,且在 1980 年之前無電梯二手房中,簡裝二手房占絕大多數(shù),,精裝反而很少,。
數(shù)據(jù)挖掘
特征工程
特征工程的目的是讓這些特征更友好的作為模型的輸入,處理數(shù)據(jù)的好壞會嚴重的影響模型性能,。
這里我們對已有的 Layout 特征,,Year 特征和 Direction 特征進行處理,創(chuàng)建新特征,,刪除無用特征,,最后進行 One-hot 獨熱編碼。
處理 Layout 特征
df['Layout'].value_counts()
# 移除X房間X衛(wèi)的格式 非民住
df = df.loc[df['Layout'].str.extract('^\d(.*?)\d.*?') == '室']
df.head()
# 用 str.extract() 方法,,將"室"和"廳"都提取出來,,單獨作為兩個新特征
df['Layout_room_num'] = df['Layout'].str.extract('(^\d).*', expand=False).astype('int64')
df['Layout_hall_num'] = df['Layout'].str.extract('^\d.*?(\d).*', expand=False).astype('int64')
處理 Year 特征
# 將連續(xù)數(shù)值型特征 Year 離散化,做分箱處理
# 如何分箱還要看實際業(yè)務需求,,這里為了方便,,使用了pandas的 qcut 采用中位數(shù)進行分割,分割數(shù)為8等份
df['Year'] = pd.qcut(df['Year'], 8).astype('object')
df['Year'].value_counts()
處理 Direction 特征
df['Direction'].value_counts()
# 寫函數(shù) direct_func 來整理上面較亂的 Direction
def direct_func(x):
if not isinstance(x,str):
raise TypeError
x = x.strip()
x_len = len(x)
x_list = pd.unique([y for y in x])
if x_len != len(x_list):
return 'no'
if (x_len == 2) & (x not in d_list_two):
m0 = x[0]
m1 = x[1]
return m1+m0
elif (x_len == 3) & (x not in d_list_three):
for n in d_list_three:
if (x_list[0] in n) & (x_list[1] in n) & (x_list[2] in n):
return n
elif (x_len == 4) & (x not in d_list_four):
return d_list_four[0]
else:
return x
# 通過 apply() 方法將 Direction 數(shù)據(jù)格式轉(zhuǎn)換
d_list_one = ['東','西','南','北']
d_list_two = ['東西','東南','東北','西南','西北','南北']
d_list_three = ['東西南','東西北','東南北','西南北']
d_list_four = ['東西南北']
df['Direction'] = df['Direction'].apply(direct_func)
df = df.loc[(df['Direction']!='no')&(df['Direction']!='nan')]
df['Direction'].value_counts()
創(chuàng)建新特征
# 根據(jù)對業(yè)務的理解,,定義新特征,,然后觀察這些新特征對模型有什么影響
# 根據(jù)已有特征創(chuàng)建新特征
df['Layout_total_num'] = df['Layout_room_num'] + df['Layout_hall_num']
df['Size_room_ratio'] = df['Size']/df['Layout_total_num']
刪除無用特征
df = df.drop(['Layout','PerPrice','Garden', 'District'], axis=1)
df.head()
One-hot 獨熱編碼 是將定類的非數(shù)值型類型量化 的一種方法,在pandas 中使用 get_dummies() 方法實現(xiàn),。這里使用一個自定義的封裝的函數(shù)實現(xiàn)了定類數(shù)據(jù)的自動量化處理,。
def one_hot_encoder(df, nan_as_category = True):
original_columns = list(df.columns)
categorical_columns = [col for col in df.columns if df[col].dtype == 'object']
df = pd.get_dummies(df, columns= categorical_columns, dummy_na= nan_as_category)
new_columns = [c for c in df.columns if c not in original_columns]
return df, new_columns
# 對于object特征進行onehot編碼
df, df_cat = one_hot_encoder(df)
特征相關性 對數(shù)據(jù)經(jīng)過以上處理后,可以用 seaborn 的 heatmap 方法對特征相關性進行可視化,。
colormap = plt.cm.RdBu
plt.figure(figsize=(20, 20))
sns.heatmap(df.corr(), linewidth=0.1, vmax=1.0, square=True,
cmap=colormap, linecolor='white', annot=True)
heatmap 可以根據(jù)顏色觀察特征的相關性,。顏色偏紅或者偏藍都說明相關系數(shù)較大,即兩個特征對于目標變量的影響程度相似,,也就是說存在嚴重的重復信息,,會造成過擬合現(xiàn)象。
我們能通過特征相關性分析,找出哪些特征有嚴重的重疊信息,,然后擇優(yōu)選擇,。
這里還需要注意特征太多有可能會導致 heatmap 圖畫失敗。
建模預測
本次建模主要方法為:使用Cart決策樹的回歸模型 對二手房房價進行分析預測,;使用交叉驗證方法 充分利用數(shù)據(jù)集進行訓練,,避免數(shù)據(jù)劃分不均勻的影響;使用GridSearchCV方法 優(yōu)化模型參數(shù),;使用R2評分方法 對模型預測評分,。
數(shù)據(jù)劃分
# 特征變量和目標變量
features = df.drop('Price', axis=1)
prices = df['Price']
# 把分類特征都轉(zhuǎn)成數(shù)值型后有{}行{}列
print('北京二手房房價有數(shù)據(jù) {0} 條,字段 {1} 個' .format(*df.shape))
# 將數(shù)據(jù)集劃分為訓練集與測試集
features = np.array(features)
prices = np.array(prices)
# 導入 sklearn 進行訓練測試集劃分
from sklearn.model_selection import train_test_split
features_train, features_test, prices_train, prices_test = train_test_split(features, prices, test_size=0.2, random_state=0)
建立模型
# 建立模型
from sklearn.model_selection import KFold
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import make_scorer
from sklearn.model_selection import GridSearchCV
# 通過交叉認證緩解數(shù)據(jù)集過擬合的現(xiàn)象
# 建立決策樹回歸模型
# 通過GridSearchCV找到最優(yōu)深度參數(shù)(基于輸入數(shù)據(jù)[X,y] 利于網(wǎng)格搜索找到最優(yōu)的決策樹模型)
def fit_model(X, y):
cross_validator = KFold(10, shuffle=True)
regressor = DecisionTreeRegressor()
params = {'max_depth': [1,2,3,4,5,6,7,8,9,10]}
scoring_fnc = make_scorer(performance_metric)
grid = GridSearchCV(estimator=regressor, param_grid=params, scoring=scoring_fnc, cv=cross_validator)
# 網(wǎng)格搜索
grid = grid.fit(X, y)
return grid.best_estimator_
評估驗證
# 計算 R2 分數(shù)
from sklearn.metrics import r2_score
def performance_metric(y_true, y_predict):
score = r2_score(y_true, y_predict)
return score
# 調(diào)參優(yōu)化模型
# 通過可視化模型學習曲線,,觀察是否出現(xiàn)過擬合問題
# visuals 為自定義函數(shù)
import visuals as vs
# 分析模型
vs.ModelLearning(features_train, prices_train)
vs.ModelComplexity(features_train, prices_train)
optimal = fit_model(features_train, prices_train)
# 輸出最優(yōu)模型的參數(shù) 'max_depth'
print('最優(yōu)模型的參數(shù) max_depth 是: {} ' .format(optimal.get_params()['max_depth']))
predicted_value = optimal.predict(features_test)
r2 = performance_metric(prices_test, predicted_value)
# 每次交叉驗證得到的數(shù)據(jù)集不同,,因此每次運行的結(jié)果也不一定相同
print('最優(yōu)模型在測試數(shù)據(jù)上 R^2 分數(shù) {: .2f}' .format(r2))
可以看到,最理想模型的參數(shù)max_depth 是 10,,此時達到了偏差與方差的最優(yōu)平衡,。模型在測試數(shù)據(jù)上的 R2 分數(shù) 為:0.77,即二手房房價預測的準確率,。
以上,,完成了一個項目的簡單分析??梢愿倪M的方向有以下 3 個:
- 爬取數(shù)據(jù)的準確性和完整性
- 特征的進一步提取
- 不同模型的融合與實驗,,以達到最優(yōu)效果
|