用python建立房價預測模型|python數據分析建模實例

Data Castle上提供美國舊金山金縣的2014年5月至2015年5月的房屋銷售價格以及房屋的基本信的數據集。

利用這份數據集,我們可以用python建立一個房價預測模型。

先來看下數據特徵描述。

其中訓練數據主要包括10000條記錄,14個欄位,主要欄位說明如下:

第一列「銷售日期」:2014年5月到2015年5月房屋出售時的日期

第二列「銷售價格」:房屋交易價格,單位為美元,是目標預測值

第三列「卧室數」:房屋中的卧室數目

第四列「浴室數」:房屋中的浴室數目

第五列「房屋面積」:房屋裡的生活面積

第六列「停車面積」:停車坪的面積

第七列「樓層數」:房屋的樓層數

第八列「房屋評分」:King County房屋評分系統對房屋的總體評分

第九列「建築面積」:除了地下室之外的房屋建築面積

第十列「地下室面積」:地下室的面積

第十一列「建築年份」:房屋建成的年份

第十二列「修復年份」:房屋上次修復的年份

第十三列"緯度":房屋所在緯度

第十四列「經度」:房屋所在經度

1,準備工作:

環境:win10+Anaconda +jupyter Notebook

導入相關的模塊並讀取數據:

#數據處理包導入import numpy as npimport pandas as pd#畫圖包導入import matplotlib.pyplot as pltplt.style.use(stylex="ggplot")import missingno as msnoimport seaborn as snssns.set()#讀取數據train_names = ["sales_time", "sales_price", "bedroom_num", "bathroom_num", "house_area", "park_space", "floor_num", "house_score", "covered_area", "basement_area", "yearbuilt", "yearremodadd", "lng", "lat"]train = pd.read_csv("kc_train.csv",names=train_names)

  • 查看數據集大小

train.shape#輸出:(10000, 14)

  • 查看數據類型

train.info()#輸出<class pandas.core.frame.DataFrame>RangeIndex: 10000 entries, 0 to 9999Data columns (total 14 columns):sales_time 10000 non-null int64sales_price 10000 non-null int64bedroom_num 10000 non-null int64bathroom_num 10000 non-null float64house_area 10000 non-null int64park_space 10000 non-null int64floor_num 10000 non-null float64house_score 10000 non-null int64covered_area 10000 non-null int64basement_area 10000 non-null int64yearbuilt 10000 non-null int64yearremodadd 10000 non-null int64lng 10000 non-null float64lat 10000 non-null float64dtypes: float64(4), int64(10)memory usage: 1.1 MB

看到「sales_time」,「yearbuilt」,「yearremodadd」實際應該為日期對象,但是原始數據集中是數值對象,需要把數據類型轉換過來,我們留在數據處理中處理。

  • 查看缺失值

train.isnull().sum()#輸出sales_time 0sales_price 0bedroom_num 0bathroom_num 0house_area 0park_space 0floor_num 0house_score 0covered_area 0basement_area 0yearbuilt 0yearremodadd 0lng 0lat 0dtype: int64

此數據集沒有空值。

2,數據處理

數據處理的內容主要是對數據集進行數據清洗和加工,然數據集變得更利於下一步分析。

具體來說數據清洗包括:查漏,去重,補缺,糾錯,而數據加工就是對數據集欄位進行提取,計算,分組,轉換等操作。

  • 缺失值處理

對於數值型數據,可用該列的數據的均值或者中位數進行替換。

對於分類型數據,可利用該列數據的出現頻數最多的數據(眾數)來填充。

有時候也可以直接捨去有缺失值的記錄。

  • 數據格式處理

包括處理字母大小寫,亂碼,數據格式,數據類型等。比如這份數據中,本應是日期類型的數據,在數據集中確是數值型數據,需要轉換為正確的數據類型。

train = pd.read_csv("kc_train.csv",names=train_names,parse_dates=["sales_time","yearbuilt",yearremodadd])train.info()#輸出<class pandas.core.frame.DataFrame>RangeIndex: 10000 entries, 0 to 9999Data columns (total 14 columns):sales_time 10000 non-null datetime64[ns]sales_price 10000 non-null int64bedroom_num 10000 non-null int64bathroom_num 10000 non-null float64house_area 10000 non-null int64park_space 10000 non-null int64floor_num 10000 non-null float64house_score 10000 non-null int64covered_area 10000 non-null int64basement_area 10000 non-null int64yearbuilt 10000 non-null datetime64[ns]yearremodadd 10000 non-null objectlng 10000 non-null float64lat 10000 non-null float64dtypes: datetime64[ns](2), float64(4), int64(7), object(1)memory usage: 1.0+ MB

pandas的IO函數,提供了在讀取數據時,處理日期對象的參數parse_dates,可以在讀取數據時,把想要轉換為日期對象的欄位,以列表的形式傳入參數。

3.探索性數據分析(EDA)

在深入機器學習或統計建模之前,EDA是一個重要的步驟,EDA目的是最大化對數據的直覺,完成這個事情的方法只能是結合統計學的圖形以各種形式展現出來。

  • 1,先看下數據集中的房價分布

train.sales_price.describe()#輸出count 1.000000e+04mean 5.428749e+05std 3.729258e+05min 7.500000e+0425% 3.225000e+0550% 4.507000e+0575% 6.450000e+05max 6.885000e+06Name: sales_price, dtype: float64

可視化

plt.figure(figsize = (10,5))print("skew: ",train.sales_price.skew())sns.distplot(train[sales_price])

通常將要預測的值稱為目標變數(target variable)。我們可以看到目標變數呈現偏態分布。

當使用回歸方法時,如果目標變數出現偏斜,則有必要對目標變數進行對數變換(log-transform)。通過對數變換,可以改善數據的線性度。

對目標變數進行對數變換

target = np.log(train.sales_price)plt.figure(figsize = (10,5))sns.distplot(target)#利用seaborn庫繪製

通過變換,分布更接近正態分布。

  • 2,檢測數值特徵和目標變數之間的相關性

corrMat = train[[sales_price,bedroom_num,bathroom_num,house_area,park_space,floor_num,house_area,covered_area,basement_area,yearremodadd,lng,lat]].corr()mask = np.array(corrMat)mask[np.tril_indices_from(mask)] = Falseplt.subplots(figsize=(20,10))plt.xticks(rotation=60)#設置刻度標籤角度sns.heatmap(corrMat, mask=mask,vmax=.8, square=True,annot=True)

print(corr["sales_price"].sort_values(ascending=False))#輸出sales_price 1.000000house_area 0.698923house_score 0.667086covered_area 0.600657bathroom_num 0.533221basement_area 0.328690bedroom_num 0.314395lng 0.304946floor_num 0.240563park_space 0.094499lat 0.027786Name: sales_price, dtype: float64

我們利用Pearson Correlation從原始特徵中選擇出一些最有效特徵。

選擇合適的特徵是項技術活,需要考慮特徵和最終結果之間的相互關係——例如,身高這個特徵描述的是一個人外表的某個方面,但是不能說明這個人學習成績如何,所以預測學習成績時,我們沒必要去測量每個人的身高。

4,構建房價預測模型

  • 構造特徵向量與目標向量

features = [house_area, house_score, covered_area, bathroom_num, basement_area, bedroom_num, lng, floor_num, "yearremodadd", "park_space" ]X = train[features]y = np.log(train[sales_price])print(X.shape,y.shape)

  • 特徵預處理

from sklearn.preprocessing import MinMaxScalerX_copy = X[:]scaler = MinMaxScaler()X_transformed = scaler.fit_transform(X_copy)

現實中,物體不同特徵的取值範圍會非常廣,它們的值域可能存在天壤之別。

例如,測量動物的屬性,會得到下面這樣千差萬別的特徵值。

? 腿的數量:大多數動物有0到8條腿,但也有比這多得多的!

? 體重:從幾微克到上百噸都有可能,有的藍鯨重達190噸!

對於藉助數學方法來比較特徵的演算法而言,它們很難理解特徵在規模、範圍和單位上的差異。如果我們在多種演算法中使用上述特徵,體重由於數值較大,可能都會是最顯著的特徵,但特徵值大小實際上與該特徵的分類效果沒有任何關係。

不同特徵的取值範圍千差萬別,常見的解決方法是對不同的特徵進行規範化,使它們的特徵值落在相同的值域或從屬於某幾個確定的類別,比如小、中和大。

選擇最具區分度的特徵、創建新特徵等都屬於預處理的範疇。

scikit-learn 的預處理工具:

? 為使每條數據各特徵值的和為1,使用 sklearn.preprocessing.Normalizer 。

? 為使各特徵的均值為0,方差為1,使用 sklearn.preprocessing.StandardScaler ,常用作規範化的基準。

? 為將數值型特徵的二值化,使用 sklearn.preprocessing.Binarizer ,大於閾值的為1,反之為0。

  • 創建訓練集和測試集

from sklearn.model_selection import train_test_splitX_train,X_test,y_train,y_test = train_test_split(X_transformed,y, random_state=1,test_size=.2)

使用scikit-learn里的train_test_split()函數生成一份訓練集和一份測試集。 使用這種方式劃分數據,使我們能評估當模型面對以前從未遇到的數據時,它的執行情況會怎樣。 如果將測試數據都用來訓練模型,那將會很難判斷模型是不是過度擬合了。

train_test_split() 會返回4個對象

X_train:用作訓練數據的一個子集X_test: 用作測試數據的一個子集--會被用來測試訓練好的模型y_train:與 X_train對應的目標變數sales_pricey_test: 與 X_test對應的目標變數sales_price

  • 建立模型

#線性回歸from sklearn import linear_modellm = linear_model.LinearRegression()model = lm.fit(X_train,y_train)print(model.intercept_,model.coef_)#輸出

  • 評估模型

我們可以使用R-square(擬合優度)指標來評估模型性能。

R平方值是數據與擬合回歸線的接近程度的一種度量,它的取值在0到1之間,1意味著目標中的所有方差都由數據解釋。

一般來說,較高的R平方值意味著更好的擬合。

model.score(X_test,y_test)print (R^2 is:
, model.score(X_test,y_test))#輸出

這標誌著我們的特徵變數能解釋目標變數中約72%的差異,一般來說擬合優度在0.7以上,我們就認為模型是可靠的。

至此,我們已經根據訓練集,完成了預測模型的建立。

接下來,就是利用預測模型對測試集生成預測。

  • 生成預測

test = pd.read_csv("kc_test.csv",names=test_names,parse_dates=["sales_time","yearbuilt"])features = [house_area, house_score, covered_area, bathroom_num, basement_area, bedroom_num, lng, floor_num, "yearremodadd", "park_space" ]X2 = test[features]scaler_test = scaler.fit_transform(test[features])model.predict(scaler_test)

最後需要把預測轉換成正確的形式。記住,要反向使用log(),執行exp()。因此,用np.exp()來做預測,因為之前已經取了對數。

final_predicts = np.exp(model.predict(scaler_test))

well done!

關於模型的評估

我們把數據集分為訓練集和測試集,用訓練集訓練演算法,在測試集上評估效果。倘若碰巧走運,測試集很簡單,我們就會覺得演算法表現很出色。反之,我們可能會懷疑演算法很糟糕。也許由於我們一時不走運,就把一個其實很不錯的演算法給拋棄了,這豈不是很可惜。

交叉檢驗能解決上述一次性測試所帶來的問題。既然只切一次有問題,那就多切幾次,多進行幾次實驗。每次切分時,都要保證這次得到的訓練集和測試集與上次不一樣,還要確保每條數據都只能用來測試一次。

演算法描述如下:

(1) 將整個大數據集分為幾個部分(fold )

(2) 對於每一部分執行以下操作:

? 將其中一部分作為當前測試集

? 用剩餘部分訓練演算法

? 在當前測試集上測試演算法

(3) 記錄每次得分及平均得分。

(4) 在上述過程中,每條數據只能在測試集中出現一次,以減少(但不能完全規避)運氣成分。

scikit-learn 提供了幾種交叉檢驗方法。有個輔助函數實現了上述交叉檢驗步驟。

from sklearn.cross_validation import cross_val_score

利用交叉檢驗評估模型:

#線性回歸from sklearn import linear_modellm = linear_model.LinearRegression()#交叉檢驗評估模型from sklearn.model_selection import cross_val_score#得到5次交叉檢驗的誤差,注意這裡cross_val_score()前面用了負號,得到的是每個回歸模型的平均絕對值誤差scores = -cross_val_score(lm,X_train,y_train,cv=5,scoring=neg_mean_absolute_error)print(scores)#求平均值,作為誤差結果import numpy as npprint(np.mean(scores))#輸出[ 0.22080097 0.2179246 0.21562791 0.21614302 0.21544286]0.217187872385

相關原理

Linear Regression線性回歸,是最為人熟知的建模技術之一。線性回歸通常是人們在學習預測模型時首選的技術之一。在這種技術中,因變數是連續的,自變數可以是連續的也可以是離散的,回歸線的性質是線性的。

線性回歸使用最佳的擬合直線(也就是回歸線)在因變數(Y)和一個或多個自變數(X)之間建立一種關係。

用一個方程式來表示它,即Y=a+b*X + e,其中a表示截距,b表示直線的斜率,e是誤差項。這個方程可以根據給定的預測變數(s)來預測目標變數的值。

用最小二乘法求得最佳擬合直線

對於觀測數據,它通過最小化每個數據點到線的垂直偏差平方和來計算最佳擬合線。

參考文章:你應該掌握的7種回歸技術


推薦閱讀:

R語言起步--excel透視表功能實現
吉利帝豪GS--車主洞察研究
通俗易懂-數據分析學生是怎麼玩天天酷跑的
用戶畫像學習

TAG:數據分析 | Python |