机器学习实战小项目之波士顿房价预测
前言
波士顿房价预测项目是一个简单的回归模型,通过该项目的学习可以学会一些关于机器学习库sklearn
的基本用法和一些基本的数据处理方法。
实现整个模型之前,首先导入一些用到的库,如下代码所示:
import pandas as pd
import numpy as np
import warnings
from sklearn.preprocessing import StandardScaler
#from sklearn.cross_validation import cross_val_score, ShuffleSplit
from sklearn.metrics import r2_score
from sklearn.model_selection import KFold
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import make_scorer
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import mutual_info_regression
from sklearn.preprocessing import MinMaxScaler
warnings.filterwarnings('ignore')
定义模型评估标准
建立模型之前,首先定义评估标准,本次模型评估标准采用的是均方误差(mse),具体实现代码如下所示:
def mse_cv(model,X,y):
mse = -cross_val_score(model,X,y,scoring="neg_mean_squared_error",cv=5)
return mse
数据预处理
整个模型的第一步需要对数据进行一些预处理,这些数据处理过程包括标准化,特征选择等。
加载数据集
首先,加载数据集,并打印出数据集的前五条信息,对数据有一个直观的了解,并将数据集标签和特征进行分离。
data = pd.read_csv("波士顿房价训练集.csv",engine="python")
data = pd.DataFrame(data)
print(data.head())
train_y = data['MEDV'] #数据集标签
train_x = data.drop('MEDV',axis) #去掉数据集的特征
进一步对数据进行分析,其中,数据的一些字段,分别表示如下含义:
CRIM:城镇人均犯罪率。
ZN:住宅用地超过 25000 sq.ft. 的比例。
INDUS:城镇非零售商用土地的比例。
CHAS:查理斯河空变量(如果边界是河流,则为1;否则为0)。
NOX:一氧化氮浓度。
RM:住宅平均房间数。
AGE:1940 年之前建成的自用房屋比例。
DIS:到波士顿五个中心区域的加权距离。
RAD:辐射性公路的接近指数。
TAX:每 10000 美元的全值财产税率。
PTRATIO:城镇师生比例。
B:1000(Bk-0.63)^ 2,其中 Bk 指代城镇中黑人的比例。
LSTAT:人口中地位低下者的比例。
MEDV:自住房的平均房价,以千美元计。
特征处理
波士顿房价数据集包含了13个特征,训练集总共404条数据,而测试集包含了102条数据,在整个模型实现之前,需要对数据集做一下简单的特征处理。
特征预处理主要包含以下几个方面:
- 标准化
标准化的代码实现如下所示:
mean = train_x.mean(axis=0)
train_x -= mean
std = train_x.std(axis = 0)
train_x /= std
- 特征筛选
sklearn
库中的feature_selection
类提供了一个函数mutual_info_regression
,以实现特征与标签之间的互信息,互信息度量 X 和 Y 共享的信息,它度量知道这两个变量其中一个,对另一个不确定度减少的程度。,房价预测中可以通过一些参数设置,实现特征筛选。具体实现代码如下所示,通过参数holder
设置,保留不同的变量
from sklearn.feature_selection import mutual_info_regression
def features_selection(features,target,holder):
mi = mutual_info_regression(features,target)
col = [col for col in features.columns] #获取所有列名
mi = mi.tolist()
list2tuple = []
list2tuple = zip(col,mi) #元组(相关系数和字段名)
corr = list(list2tuple)
corr_remove = []
for i in range(len(corr)):
if corr[i][1]<holder:
corr_remove.append(corr[i][0])
return corr_remove
- 特征重要性分别
可以通过Lasso回归实现特征重要性分布,通过特征重要性分布,也可以实现特征筛选,具体如下代码所示:
import matplotlib.pyplot as plt
FI_lasso = pd.DataFrame({"features_importance":lasso.coef_},index=features.columns)
FI_lasso.sort_values('features_importance',ascending=False)
FI_lasso[FI_lasso["features_importance"]!=0].sort_values("features_importance").plot(kind="barh",figsize=(15,7))
plt.xticks(rotation=90)
plt.show()
- 标签处理
除了对特征处理之外,还可以根据标签的分布,对标签进行处理,这些处理,主要是异常值处理,处理方式包括删除异常值,替代异常值等。在处理之前,首先,可以绘制标签的分布图,如下所示:
import scipy.stats as st
y = data_label['MEDV']
sns.distplot(y, kde=False, fit=st.norm)
总体而言,数据的分布应该符合正态分布,经过统计,训练集包含了14个最大值,所以,可以对这14个最大值进行处理,包括删除,或者将其替换为平均值。删除这14个最大值的代码如下所示:
#删除最大值的行,data表示数据,max_value表示最大值
def remove_max_value(data,max_value):
data_max_value = data.loc[data['MEDV'].isin([max_value])] #定位最大值出现的行数
remove_index = data_max_value.index
data_drop_max_value = data.drop(remove_index) #去掉前七个最大值
return data_drop_max_value
模型选择
为了验证不同的模型,不妨挑选最常见的回归模型进行测试,根据结果再对模型进行选择,具体实现代码如下所示:
选择模型进行评估,共13个模型
- LinerRegression
- Ridge
- Lasso
- Random Forrest
- Gradient BOOsting Regression
- Support Vector Regression
- Liner Support Vector Regression
- ElasticNet
- Stochhastic Gradient Descent
- BayesianRidge
- KernelRidge
- ExtraTreesRegression
- XgBoost
from sklearn.model_selection import cross_val_score, GridSearchCV, KFold
from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Ridge
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor, ExtraTreesRegressor
from sklearn.svm import SVR, LinearSVR
from sklearn.linear_model import ElasticNet, SGDRegressor, BayesianRidge
from sklearn.kernel_ridge import KernelRidge
from xgboost import XGBRegressor
# 定义模型
models = [LinearRegression(),
Ridge(),
Lasso(alpha=0.001,max_iter=10000),
![1.JPG](https://upload-images.jianshu.io/upload_images/3130464-934ea678e4e77828.JPG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
RandomForestRegressor(),
GradientBoostingRegressor(),
SVR(),
LinearSVR(),
ElasticNet(alpha=0.001,max_iter=10000),
SGDRegressor(max_iter=1000,tol=1e-3),
BayesianRidge(),
KernelRidge(alpha=0.6,kernel='polynomial',degree=2,coef0=2.5),
ExtraTreesRegressor(),
XGBRegressor()]
依次对以上模型进行数据拟合和评分,如下所示:
# 输出13个回归模型的评分
for name,model in zip(names,models):
score = rmse_cv(model,X_train,y_train)
print("{}: {:.6f}, {:.4f}".format(name,score.mean(),score.std()))
网格化参数搜索
sklearn
提供了网格化参数搜索的函数,允许模型对参数进行自动搜索,定义网格化参数搜索的代码如下所示:
class grid():
def __init__(self,model):
self.model = model
def grid_get(self,X,y,param_grid):
grid_search = GridSearchCV(self.model,param_grid,cv=5,scoring="neg_mean_squared_error")
grid_search.fit(X,y)
print(grid_search.best_params_,np.sqrt(-grid_search.best_score_))
grid_search.cv_results_['mean_test_score'] = np.sqrt(-grid_search.cv_results_['mean_test_score'])
print(pd.DataFrame(grid_search.cv_results_)[['params','mean_test_score','std_test_score']])
利用参数自动搜索,可以得到性能最好的一组参数,以support vector Regression
为例,具体实现代码如下所示:
grid(SVR()).grid_get(X_train,y_train,{'C':range(101,601,50),'kernel':["rbf"],"gamma":[0.0512,0.1,0.2,0.4],"epsilon":[0.064,0.2,0.4,0.6,0.8,0.1,0.128]})
事实上,通过对不同的模型进行参数自动搜索,可以确定不同模型的最优参数,再将这些得到最优参数的模型进行进一步的模型融合(加权融合,stack等)。可以实现更为复杂(特征更多,数据量更大)的回归问题。
模型实现
由于数据量和特征较少,选择更加复杂的模型会导致严重的过拟合,所以,简单做一下特征筛选并采用参数自动化搜索的方案,具体的代码如下所示:
# 参数自动化搜索建立拟合模型
def fit_model(features,prices):
cross_vaildator = KFold(n_splits=5,random_state=1,shuffle=True) #5折交叉验证
regressor = SVR() # SVR回归模型(带核函数的支持向量机模型)
#模型参数构成的字典
params = {'C':[2,4,6,8,10,15,20,25,30,100,120,150],'kernel':["rbf"],"gamma":[0.0032,0.0048,0.0064,0.0128,0.0256,0.0512,0.128,0.25,0.5,1.0],"epsilon":[0.064,0.8,0.1,0.128,0.256,0.5,1.0]}
#参数自动化搜索,第一个表示回归器,评分标准是mse。使用交叉验证的方式
grid = GridSearchCV(regressor,params,scoring="neg_mean_squared_error",cv=cross_vaildator)
grid =grid.fit(features,prices)
return grid.best_estimator_ #返回拟合最好的一组模型参数
通过以上代码,实现了参数自动化搜索的模型,并且能够返回最好的模型参数,根据以上模型,可以实现预测,如下代码所示:
optimal_reg = fit_model(X_train,y_train) #用训练集数据训练模型
y_fit=optimal_reg.predict(X_test) #利用训练好的模型做出预测(测试集输出)
y_train_fit = optimal_reg.predict(X_train) #预测训练集输出