摘要:本次實戰(zhàn)項目的主要目的是分析北京二手房房價,項目源自博文入門數(shù)據(jù)分析最好的實戰(zhàn)項目一和入門數(shù)據(jù)分析最好的實戰(zhàn)項目二。
本次實戰(zhàn)項目的主要目的是分析北京二手房房價,項目源自博文:入門Python數(shù)據(jù)分析最好的實戰(zhàn)項目(一)和入門Python數(shù)據(jù)分析最好的實戰(zhàn)項目(二)。本篇文章僅記錄博主在學習過程中的思路。
首先我們要對數(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í)行結果:
分析目的:
分析有無電梯兩種二手房對數(shù)量和價格。
使用方法:
采用seaborn完成可視化。
觀察結果:
我們發(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í)行結果:
分析目的:
分析不同的樓層二手房數(shù)量。
使用方法:
采用seaborn完成可視化。
觀察結果:
其中 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í)行結果:
分析目的:
分析不同戶型的數(shù)量。
使用方法:
采用seaborn完成可視化。
觀察結果:
這個特征分類下有很多不規(guī)則的命名,以上特征是不能作為機器學習模型的數(shù)據(jù)輸入的,需要使用特征工程進行相應的處理。
代碼:
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í)行結果:
分析目的:
分析不同區(qū)域的房價和數(shù)量,并進行對比。
使用方法:
用pandas的網(wǎng)絡透視功能groupby分組排序。
區(qū)域特征可視化采用seaborn完成。
顏色使用調(diào)色板palette參數(shù),顏色越淺數(shù)量越少,反之越多。
觀察結果:
二手房每平方米單價對比:西城區(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í)行結果:
分析目的:
分析不同裝修程度的二手房數(shù)量和房價。
使用方法:
采用seaborn完成可視化。
觀察結果:
對于數(shù)量來說,精裝修的二手房最多,簡裝其次;對于價格來說,毛坯房價格最高,其次是精裝修的。
代碼:
# 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í)行結果:
分析目的:
分析不同大小的二手房和價格的關系。
使用方法:
通過distplot和 kdeplot 繪制柱狀圖觀察 Size 特征的分布情況,屬于長尾類型的分布,這說明有很多面積很大且超出正常范圍的二手房。
通過 regplot 繪制了 Size 和 Price 之間的散點圖,發(fā)現(xiàn) Size 特征基本與Price呈現(xiàn)線性關系,符合基本常識,面積越大,價格越高。
觀察結果:
有兩組明顯的異常點:面積不到 10 平米但價格超出 10000 萬和面積超過了 1000 平米價格很低兩種情況。
經(jīng)過查看發(fā)現(xiàn)這兩組異常值分別是別墅和商用房,因此出現(xiàn)異常,故將其移除再次觀察Size分布和Price關系。
這里也說明我們在觀察數(shù)據(jù)的時候,要緊密結合實際業(yè)務需求來分析,才能得出更準確的結果。
Year 特征分析代碼:
# Year 特征分析 grid = sns.FacetGrid(df, row="Elevator", col="Renovation", palette="seismic", size=4) grid.map(plt.scatter, "Year", "Price") # grid.add_legend()
執(zhí)行結果:
分析目的:
分析不同年代對房價變化的影響。
使用方法:
在 Renovation 和 Elevator 的分類條件下,使用 FacetGrid 分析 Year 特征
觀察結果:
觀察數(shù)據(jù)可視化圖表可以看出,整個二手房房價趨勢是隨著時間增長而增長的,2000 年以后建造的二手房房價相較于 2000 年以前有很明顯的價格上漲。此外,1980年之前幾乎不存在有電梯二手房數(shù)據(jù),說明1980年之前還沒有大面積安裝電梯,且在 1980 年之前無電梯二手房中,簡裝二手房占絕大多數(shù),精裝反而很少。
特征工程的目的是讓這些特征更友好的作為模型的輸入,處理數(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ù)集不同,因此每次運行的結果也不一定相同 print("最優(yōu)模型在測試數(shù)據(jù)上 R^2 分數(shù) {: .2f}" .format(r2))
可以看到,最理想模型的參數(shù)max_depth是 10,此時達到了偏差與方差的最優(yōu)平衡。模型在測試數(shù)據(jù)上的 R2 分數(shù)為:0.77,即二手房房價預測的準確率。
以上,完成了一個項目的簡單分析。可以改進的方向有以下 3 個:
爬取數(shù)據(jù)的準確性和完整性
特征的進一步提取
不同模型的融合與實驗,以達到最優(yōu)效果
不足之處,歡迎指正
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/42030.html
摘要:入門數(shù)據(jù)分析最好的實戰(zhàn)項目二數(shù)據(jù)初探首先導入要使用的科學計算包可視化以及機器學習包。檢查缺失值情況發(fā)現(xiàn)了數(shù)據(jù)集一共有條數(shù)據(jù),其中特征有明顯的缺失值。 作者:xiaoyu 微信公眾號:Python數(shù)據(jù)科學 知乎:python數(shù)據(jù)分析師 目的:本篇給大家介紹一個數(shù)據(jù)分析的初級項目,目的是通過項目了解如何使用Python進行簡單的數(shù)據(jù)分析。數(shù)據(jù)源:博主通過爬蟲采集的鏈家全網(wǎng)北京二手房數(shù)據(jù)(...
摘要:入門數(shù)據(jù)分析最好的實戰(zhàn)項目二數(shù)據(jù)初探首先導入要使用的科學計算包可視化以及機器學習包。檢查缺失值情況發(fā)現(xiàn)了數(shù)據(jù)集一共有條數(shù)據(jù),其中特征有明顯的缺失值。 作者:xiaoyu 微信公眾號:Python數(shù)據(jù)科學 知乎:python數(shù)據(jù)分析師 目的:本篇給大家介紹一個數(shù)據(jù)分析的初級項目,目的是通過項目了解如何使用Python進行簡單的數(shù)據(jù)分析。數(shù)據(jù)源:博主通過爬蟲采集的鏈家全網(wǎng)北京二手房數(shù)據(jù)(...
摘要:作者微信公眾號數(shù)據(jù)科學知乎數(shù)據(jù)分析師上一篇和大家分享了一個入門數(shù)據(jù)分析的一個小項目北京二手房房價分析,鏈接如下入門數(shù)據(jù)分析最好的實戰(zhàn)項目一文章在發(fā)布之后看到有不少感興趣的朋友給我點了贊,感謝大家的支持了。 作者:xiaoyu 微信公眾號:Python數(shù)據(jù)科學 知乎:python數(shù)據(jù)分析師 上一篇和大家分享了一個入門數(shù)據(jù)分析的一個小項目 北京二手房房價分析,鏈接如下: 入門Python...
閱讀 841·2021-11-16 11:56
閱讀 1653·2021-11-16 11:45
閱讀 3108·2021-10-08 10:13
閱讀 4094·2021-09-22 15:27
閱讀 726·2019-08-30 11:03
閱讀 642·2019-08-30 10:56
閱讀 945·2019-08-29 15:18
閱讀 1737·2019-08-29 14:05