没怎么做过kaggle的题目,对机器学习的套路还不是非常熟悉,然后前段时间碰到了一个回归的问题,竟然不知道如何下手,Kaggle上有一个房价预测的基础回归问题,机器学习回归就从这里开始好了。
学习资料:https://www.kaggle.com/marsggbo/kaggle
\quad 完整的机器学习算法解决房价预测需要处理以下几个问题:
1、 理解问题:观察每个变量特征的意义以及对于问题的重要度
2、 理解主要特征:也就是最终的目的变量—房价
3、 基础的数据清洗:对一些缺失的,异常点和分类数据进行处理
4、 测试假设
我也将按照这个步骤来解决这个问题
#导入需要的模块
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
#用来绘图的,封装了matplot
#一旦导入了seaborn,matplotlib的作图风格会被覆盖为seaborn
import seaborn as sns
from scipy import stats
from scipy.stats import norm #生成正态分布的离散变量
from sklearn.preprocessing import StandardScaler #计算训练数据集的平均值和标准差,以便测试集使用相同的变换
#导入数据
data_train = pd.read_csv("/home/zxy/PycharmProjects/Kagglemarsggbo/data/train.csv")
# print(data_train)
print(data_train['SalePrice'].describe())
输出为:
count 1460.000000
mean 180921.195890
std 79442.502883
min 34900.000000
25% 129975.000000
50% 163000.000000
75% 214000.000000
max 755000.000000
Name: SalePrice, dtype: float64
可以看出,SalePrice变量没有无效和非数值的数据,然后作者还提供了一种图示化方法来展示salePrice
sns.distplot(data_train['SalePrice'])
plt.show()
可以看出房价是呈现正态分布的。同时作者还介绍了2个统计学的概念:峰度(Kurtosis)和偏度(Skewness),其中峰度是描述某变量所有取值分布形态抖缓程度的统计量。它是和正太分布相比较的。
峰度
偏度
6. Skewness = 0 分布形态与正太分布偏度相同
7. Skewness > 0 正偏差数值较大,为正偏或右偏。长尾巴拖在左边。
8. Skewness < 0 负偏差数值较大,为负偏或左偏。长尾巴拖在左边。
9. 计算公式:
打印出这两个值:
print("Skewness: %f" % data_train['SalePrice'].skew())
print("Kurtosis %f" % data_train['SalePrice'].kurt())
结合上面的图形容易看出,长尾巴确实拖在右边,而且高峰陡峭。
#CentralAir
var = 'CentralAir'
data = pd.concat([data_train['SalePrice'], data_train[var]], axis=1)
fig = sns.boxplot(x = var, y = 'SalePrice', data=data)
fig.axis(ymin=0, ymax=800000);
plt.show()
# OverallQual 总体评价
var = 'OverallQual'
data = pd.concat([data_train['SalePrice'], data_train[var]], axis=1)
fig = sns.boxplot(x = var, y = 'SalePrice', data=data)
fig.axis(ymin=0, ymax=800000)
plt.show()
# OverallQual 总体评价
# var = 'OverallQual'
# data = pd.concat([data_train['SalePrice'], data_train[var]], axis=1)
# fig = sns.boxplot(x = var, y = 'SalePrice', data=data)
# fig.axis(ymin=0, ymax=800000)
# plt.show()
#YearBuilt boxplot
var = 'YearBuilt'
data = pd.concat([data_train['SalePrice'], data_train[var]], axis=1)
data.plot.scatter(x=var, y="SalePrice", ylim=(0, 800000))
plt.show()
第一个箱线图看得不是很明显,所以用点图来表示,
可以看出,建造年份越晚,价格越高。
#Neighborhood
var = 'Neighborhood'
data = pd.concat([data_train['SalePrice'], data_train[var]], axis=1)
f, ax = plt.subplots(figsize=(26,12))
fig = sns.boxplot(x=var, y="SalePrice", data=data)
fig.axis(ymin=0, ymax=800000)
plt.show()
#LotArea 地表面积
var = 'LotArea'
data = pd.concat([data_train['SalePrice'], data_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000))
plt.show()
#GrliveArea 生活面积
var = 'GrLivArea'
data = pd.concat([data_train['SalePrice'], data_train[var]], axis=1)
data.plot.scatter(x = var, y = 'SalePrice', ylim=(0,800000))
plt.show()
#TotalBsmSF地下室总面积
var = 'TotalBsmtSF'
data = pd.concat([data_train['SalePrice'], data_train[var]], axis=1)
data.plot.scatter(x = var, y = 'SalePrice', ylim=(0, 800000))
plt.show()
#MiscVal 附加值
var = 'MiscVal'
data = pd.concat([data_train['SalePrice'], data_train[var]], axis=1)
data.plot.scatter(x = var, y='SalePrice', ylim=(0, 800000))
plt.show()
# GarageArea/GarageCars 车库
var = ['GarageArea', 'GarageCars']
for index in range(2):
data = pd.concat([data_train['SalePrice'], data_train[var[index]]], axis=1)
data.plot.scatter(x=var[index], y='SalePrice', ylim=(0, 800000))
plt.show()
从上面的图看出房价与车库面试和容量车辆数呈现线性关系,所以入选主特征。
\quad 上面对特征变量的分析是比较模糊的,为了让我们更好的评估我们的变量是否对结果有用需要做到以下几点:
代码如下:
corrmat = data_train.corr() #相关系数矩阵
f, ax = plt.subplots(figsize=(20, 9))
sns.heatmap(corrmat, vmax=0.8, square=True)
plt.show()
从这个图我们可以直接看到,像素块越红表示相关性越大,所以我们可以看到与"SalePrice"相关性很强的有:
OverallQual
总体评价YearBuilt
建造年份TotalBsmSF
:地下室面积1stFlrSF
:一楼面积GrLiveArea
: 生活区面积'FullBath'
:浴室ToRmsAbvGrd
:总房间数GarageCars
: 车库可容纳车辆数GarageArea
: 车库面积from sklearn import preprocessing
f_names = ['CentralAir', 'Neighborhood']
for x in f_names:
label = preprocessing.LabelEncoder() #LabelEncoder就是对不连续的数字或者文本进行编号
data_train[x] = label.fit_transform(data_train[x])
corrmat = data_train.corr()
f, ax = plt.subplots(figsize=(20, 9))
sns.heatmap(corrmat, vmax=0.8, square=True)
plt.show()
利用这个信息可以得到,CentralAir
和Neighborhood
这两个特征对房价的影响,所以后面将不予考虑。
k = 10 #关系矩阵中将显示10个特征
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(data_train[cols].values.T) #相关系数,也可以看成协方差
sns.set(font_scale=1.25) #字体大小缩放比例?
# heatmap API:https://blog.csdn.net/cymy001/article/details/79576019
hm = sns.heatmap(cm, cbar=True, annot=True,\
square=True, fmt='.2f', annot_kws={'size':10}, yticklabels=cols.values,\
xticklabels=cols.values)
labels = cols.values
plt.show()
分析得到我们需要考虑的特征值如下:GrLKivArea(生活面积),TotRmsAbvGrd(总房间数),FullBath(浴室数量),TotalBsmSF(地下室总面积),GarageCars(车库),YearBuilt(建造年份),QverallQual(总体评价)。
#导入模型
from sklearn import preprocessing
from sklearn import linear_model, svm, gaussian_process
from sklearn.ensemble import RandomForestRegressor
from sklearn.cross_validation import train_test_split
import numpy as np
#导入数据
cols = ['OverallQual', 'GrLivArea', 'GarageCars', 'TotalBsmtSF', 'FullBath',
'TotRmsAbvGrd', 'YearBuilt']
x = data_train[cols].values
y = data_train['SalePrice'].values
x_scaled = preprocessing.StandardScaler().fit_transform(x) #归一化数据
y_scaled = preprocessing.StandardScaler().fit_transform(y.reshape(-1, 1)) #归一化数据并且拉成一个列向量
X_train, X_test, y_train, y_test = train_test_split(x_scaled, y_scaled, test_size=0.33, random_state=42)
clfs = {
'svm': svm.SVR(),
'RandomForestRegressor':RandomForestRegressor(n_estimators=400),
'BayesianRidge':linear_model.BayesianRidge()
}
for clf in clfs:
try:
clfs[clf].fit(X_train, y_train)
y_pred = clfs[clf].predict(X_test)
print(clf + " cost:" + str(np.sum(y_pred - y_test) / len(y_pred)))
except Exception as e:
print(clf + "Error:")
print(str(e))
输出结果:
svm cost:-17.967306347608588
BayesianRidge cost:-17.19150469291163
RandomForestRegressor cost:-0.9689254868891797
可以看出随机深林的损失函数最小,所以采用随机深林对模型进行预测
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
rfr = dst
data_test = pd.read_csv("/home/zxy/PycharmProjects/Kagglemarsggbo/data/test.csv")
print(data_test[cols].isnull().sum())
OverallQual 0
GrLivArea 0
GarageCars 1
TotalBsmtSF 1
FullBath 0
TotRmsAbvGrd 0
YearBuilt 0
dtype: int64
因为数据中存在缺失的值,所以不能直接predict,而且缺失值较少,所以直接用数据的均值来替代,所以接下来计算缺失值的均值即可。
cols2 = ['OverallQual', 'GrLivArea', 'FullBath', 'TotRmsAbvGrd', 'YearBuilt']
cars = data_test['GarageCars'].fillna(1.766118)
bsmt = data_test['TotalBsmtSF'].fillna(1046.117970)
data_test_x = pd.concat([data_test[cols2], cars, bsmt], axis=1)
print(data_test_x.isnull().sum())
x = data_test_x.values
y_ = rfr.predict(x)
print(y_)
print(y_.shape)
print(x.shape)
predictions = pd.DataFrame(y_, columns=['SalePrice'])
result = pd.concat([data_test['Id'], predictions], axis=1)
result.to_csv('./Predictions.csv', index=False)
至此,baseline就完成了,那么如何提高准确率呢?
##机器学习模型之Lasso参数记录
-alpha 惩罚系数