波士頓房價預測 Boston housing
這是一個波士頓房價預測的一個實戰,上一次的Titantic是生存預測,其實本質上是一個分類問題,就是根據數據分為1或為0,這次的波士頓房價預測更像是預測一個連續值,當然這也是一個非常經典的機器學習案例Boston housing
如果想了解更多的知識,可以去我的機器學習之路 The Road To Machine Learning通道
@
活動背景
波士頓房地產市場競爭激烈,而你想成為該地區最好的房地產經紀人。為了更好地與同行競爭,你決定運用機器學習的一些基本概念,幫助客戶為自己的房產定下最佳售價。幸運的是,你找到了波士頓房價的數據集,里面聚合了波士頓郊區包含多個特征維度的房價數據。你的任務是用可用的工具進行統計分析,並基於分析建立優化模型。這個模型將用來為你的客戶評估房產的最佳售價。
數據介紹


詳細代碼解釋
導入Python Packages
首先導入需要的python包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
plt.style.use('ggplot')
%load_ext klab-autotime
讀入數據 Read-In Data
將housing,csv讀入
data = pd.read_csv('../data_files/2.Boston_housing/housing.csv')
data.info()
# No 屬性 數據類型 字段描述x
# 1 CRIM Float 城鎮人均犯罪率
# 2 ZN Float 占地面積超過2.5萬平方英尺的住宅用地比例
# 3 INDUS Float 城鎮非零售業務地區的比例
# 4 CHAS Integer 查爾斯河虛擬變量 (= 1 如果土地在河邊;否則是0)
# 5 NOX Float 一氧化氮濃度(每1000萬份)
# 6 RM Float 平均每居民房數
# 7 AGE Float 在1940年之前建成的所有者占用單位的比例
# 8 DIS Float 與五個波士頓就業中心的加權距離
# 9 RAD Integer 輻射狀公路的可達性指數
# 10 TAX Float 每10,000美元的全額物業稅率
# 11 PTRATIO Float 城鎮師生比例
# 12 B Float 1000(Bk - 0.63)^ 2其中Bk是城鎮黑人的比例
# 13 LSTAT Float 人口中地位較低人群的百分數
# 14 MEDV Float (目標變量/類別屬性)以1000美元計算的自有住房的中位數


從這里可以看出來,數據一共有14個特征,並且沒有缺失值,所以我們可以不用缺失值處理,真不錯
從Package讀取Boston數據
其實在我們的sklearn庫中,就有波士頓房屋數據集,我們可以直接讀取數據集
from sklearn.datasets import load_boston
dir(load_boston())
print(load_boston().DESCR)

這里也有對數據集詳細的介紹,除此之外,我們還需要將數據集轉化了類型,變為我們熟悉的pandas.core.frame.DataFrame,之后后面的操作就是一模一樣的了
X = load_boston().data
y = load_boston().target
df = pd.DataFrame(X, columns=load_boston().feature_names)
df.head()

相關性檢驗
看看各個特征中是否有相關性,判斷一下用哪種模型比較合適
plt.figure(figsize=(12,8))
sns.heatmap(data.corr(), annot=True, fmt='.2f', cmap='PuBu')

數據不存在相關性較小的屬性,也不用擔心共線性,所以我們可以用線性回歸模型去預測
data.corr()['MEDV'].sort_values()

多變量研究
嘗試了解因變量和自變量、自變量和自變量之間的關系
sns.pairplot(data[["LSTAT","RM","PIRATIO","MEDV"]])

划分訓練集和測試集
由於數據沒有null值,並且,都是連續型數據,所以暫時不用對數據進行過多的處理,不夠既然要建立模型,首先就要進行對housing分為訓練集和測試集,取出了大概百分之20的數據作為測試集,剩下的百分之70為訓練集
X ,y = data[data.columns.delete(-1)], data['MEDV']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=888)
查看訓練集和測試集的維度

建立線性回歸模型
首先,我利用線性回歸模型對數據進行訓練,並預測測試集數據,對於具體的線性回歸的介紹,可以參考Linear Regression Machine Learning

linear_model = LinearRegression()
linear_model.fit(X_train, y_train)
coef = linear_model.coef_#回歸系數
line_pre = linear_model.predict(X_test)
print('SCORE:{:.4f}'.format(linear_model.score(X_test, y_test)))
print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y_test, line_pre))))
coef
根據結果來看,預測的score為76%左右,然后均方誤差RMSE大約是4.5,為了更好的看出預測數據的問題,我想試着可視化一下

df_coef = pd.DataFrame()
df_coef['Title'] = data.columns.delete(-1)
df_coef['Coef'] = coef
df_coef
這是線性回歸的相關系數

hos_pre = pd.DataFrame()
hos_pre['Predict'] = line_pre
hos_pre['Truth'] = y_test
hos_pre.plot(figsize=(18,8))

- 得出score為76%,從上圖得知預測的房價整體偏小,在10-35這個區間預測結果較為准確,超過這個區間預測價格偏小,可進一步對原始數據離群值做處理。
- 數據比較干凈,練習起來缺少特征工程部分的工作,而且是預測性模型,相比分類問題少了模型選擇上的空間。
評價模型
在整個數據集上評價模型
plt.scatter(y_test, line_pre,label='y')
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'k--', lw=4,label='predicted')

然后在整個數據集中評價模型
line_pre_all = linear_model.predict(X) #預測值
print('SCORE:{:.4f}'.format(linear_model.score(X,y)))
print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y, line_pre_all))))
hos_pre_all = pd.DataFrame()
hos_pre_all['Predict'] = line_pre_all
hos_pre_all['Truth'] = y
hos_pre_all.plot(figsize=(18,8))

plt.scatter(y, line_pre_all,label='y')
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=4,label='predicted')

由以上分析可知,模型在整個數據集中的評分比在測試集中要低
進一步探索和模型改進
- 嘗試使用相關性最高的3個特征量重建模型,並與原模型進行比較
- 嘗試使用其它多種算法分別建立模型,並比較模型
特征選擇重建模型
首先我嘗試相關性最高的三個特征重建模型,去與原模型比較一下
data.corr()['MEDV'].abs().sort_values(ascending=False).head(4)
由此我們得出了三個相關性最高的特征,我們將其作為自變量去建立模型

X2 = np.array(data[['LSTAT','RM','PIRATIO']])
X2_train, X2_test, y_train, y_test = train_test_split(X2, y, random_state=1,test_size=0.2)
linear_model2 = LinearRegression()
linear_model2.fit(X2_train,y_train)
print(linear_model2.intercept_)
print(linear_model2.coef_)
line2_pre = linear_model2.predict(X2_test) #預測值
print('SCORE:{:.4f}'.format(linear_model2.score(X2_test, y_test)))#模型評分
print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y_test, line2_pre))))#RMSE(標准誤差)
我們可以得到,對於預測測試集的數據的得分score明顯是沒有開始的線性回歸模型1高的,然后我們再看看,在整個數據集中它的表現

line2_pre_all = linear_model2.predict(X2) #預測值
print('SCORE:{:.4f}'.format(linear_model2.score(X2, y)))#模型評分
print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y, line2_pre_all))))#RMSE(標准誤差)

這樣比較下來,第一個模型達到的分數,即使在整個數據集中73%,但是這個模型的得分大約是67.6%,由此可以得出,第一個模型還是比這個模型優的,接下來就需要嘗試更多的模型了
數據標准化
數據集的 標准化 對scikit-learn中實現的大多數機器學習算法來說是 常見的要求 。如果個別特征或多或少看起來不是很像標准正態分布(具有零均值和單位方差),那么它們的表現力可能會較差。
所以我這里首先對數據進行了一個標准化處理
from sklearn.preprocessing import StandardScaler
ss_x = StandardScaler()
X_train = ss_x.fit_transform(X_train)
X_test = ss_x.transform(X_test)
ss_y = StandardScaler()
y_train = ss_y.fit_transform(y_train.values.reshape(-1, 1))
y_test = ss_y.transform(y_test.values.reshape(-1, 1))
模型優化和改進
接下來我就開始嘗試多種模型,希望嘗試的模型有對我的算法有幫助
X ,y = data[data.columns.delete(-1)], data['MEDV']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=9)
GradientBoosting(梯度提升)
from sklearn import ensemble
#params = {'n_estimators': 500, 'max_depth': 4, 'min_samples_split': 1,'learning_rate': 0.01, 'loss': 'ls'}
#clf = ensemble.GradientBoostingRegressor(**params)
clf = ensemble.GradientBoostingRegressor()
clf.fit(X_train, y_train)
clf_pre=clf.predict(X_test) #預測值
print('SCORE:{:.4f}'.format(clf.score(X_test, y_test)))#模型評分
print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y_test, clf_pre))))#RMSE(標准誤差)

Lasso 回歸 (Least Absolute Shrinkage and Selection Operator)
Lasso也是懲罰其回歸系數的絕對值。
與嶺回歸不同的是,Lasso回歸在懲罰方程中用的是絕對值,而不是平方。這就使得懲罰后的值可能會變成0
from sklearn.linear_model import Lasso
lasso = Lasso()
lasso.fit(X_train,y_train)
y_predict_lasso = lasso.predict(X_test)
r2_score_lasso = r2(y_test,y_predict_lasso)
print('SCORE:{:.4f}'.format( lasso.score(X_test, y_test)))#模型評分
print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y_test,y_predict_lasso))))#RMSE(標准誤差)
print('Lasso模型的R-squared值為:',r2_score_lasso)
ElasticNet 回歸
ElasticNet回歸是Lasso回歸和嶺回歸的組合
enet = ElasticNet()
enet.fit(X_train,y_train)
y_predict_enet = enet.predict(X_test)
r2_score_enet = r2(y_test,y_predict_enet)
print('SCORE:{:.4f}'.format( enet.score(X_test, y_test)))#模型評分
print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y_test,y_predict_enet))))#RMSE(標准誤差)
print("ElasticNet模型的R-squared值為:",r2_score_enet)
Support Vector Regression (SVR)
from sklearn.linear_model import ElasticNet
from sklearn.svm import SVR
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.metrics import r2_score as r2, mean_squared_error as mse, mean_absolute_error as mae
def svr_model(kernel):
svr = SVR(kernel=kernel)
svr.fit(X_train, y_train)
y_predict = svr.predict(X_test)
# score(): Returns the coefficient of determination R^2 of the prediction.
print(kernel,' SVR的默認衡量評估值值為:', svr.score(X_test,y_test))
print(kernel,' SVR的R-squared值為:', r2(y_test, y_predict))
print(kernel,' SVR的均方誤差(mean squared error)為:',mse(y_test, y_predict))
print(kernel,' SVR的平均絕對誤差(mean absolute error)為:',mae(y_test,y_predict))
# print(kernel,' SVR的均方誤差(mean squared error)為:',mse(scalery.inverse_transform(y_test), scalery.inverse_transform(y_predict)))
# print(kernel,' SVR的平均絕對誤差(mean absolute error)為:',mae(scalery.inverse_transform(y_test),scalery.inverse_transform(y_predict)))
return svr
linear 線性核函數
linear_svr = svr_model(kernel='linear')

poly 多項式核
poly_svr = svr_model(kernel='poly')

rbf(Radial Basis Function) 徑向基函數
rbf_svr = svr_model(kernel='rbf')

SVM(支持向量機)回歸-- 線性核
from sklearn.svm import SVR
linear_svr = SVR(kernel="linear")
linear_svr.fit(X_train, y_train)
linear_svr_pre = linear_svr.predict(X_test)#預測值
print('SCORE:{:.4f}'.format(linear_svr.score(X_test, y_test)))#模型評分
print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y_test, linear_svr_pre))))#RMSE(標准誤差)

SVM(支持向量機)回歸-- 多項式核
在使用SVM回歸-- 多項式核的時候,首先要對數據進行一個標准化處理
from sklearn.preprocessing import StandardScaler ss_x = StandardScaler() X_train = ss_x.fit_transform(X_train) X_test = ss_x.transform(X_test) ss_y = StandardScaler() y_train = ss_y.fit_transform(y_train.values.reshape(-1, 1)) y_test = ss_y.transform(y_test.values.reshape(-1, 1))
再進行建立模型來預測
poly_svr = SVR(kernel="poly") poly_svr.fit(X_train, y_train) poly_svr_pre = poly_svr.predict(X_test)#預測值 print('SCORE:{:.4f}'.format(poly_svr.score(X_test, y_test)))#模型評分 print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y_test, poly_svr_pre))))#RMSE(標准誤差)

決策樹回歸
from sklearn.tree import DecisionTreeRegressor tree_reg=DecisionTreeRegressor(max_depth=2) tree_reg.fit(X_train, y_train) tree_reg_pre = tree_reg.predict(X_test)#預測值 print('SCORE:{:.4f}'.format( tree_reg.score(X_test, y_test)))#模型評分 print('RMSE:{:.4f}'.format(np.sqrt(mean_squared_error(y_test,tree_reg_pre))))#RMSE(標准誤差)

最后我們會發現,利用GBDT的得分居然高達90,這是我們得到最優的一個模型了,其次就是SVR回歸的多項式核,也大概達到了85,其他的並沒有線性回歸那么優,所以對於波士頓房價預測來說,利用GBDT是最好的,這是迄今為止我遇到最好的模型
總結
- 可以發現,如果要用Gradient Boosting 算法的話,在sklearn包里調用是非常方便的,幾行代碼即可完成,大部分的工作是在數據特征提取
- 數據分析過程中,特征設計是最重要的,現在kaggle競賽很流行使用GBDT(梯度提升決策樹Gradient Boosted Decision Tree) 算法,數據分析結果的優劣其實主要在特征上,行業中做項目也是如此
- 不斷的在研究數據中培養對數據的敏感度十分重要
每日一句
Never had to laugh at other people.(沒經歷過才笑別人的疤)
如果需要數據和代碼,可以自提
- 路徑1:我的gitee
- 路徑2:百度網盤
鏈接:https://pan.baidu.com/s/1uA5YU06FEW7pW8g9KaHaaw
提取碼:5605
