首先是先导入一些必要的库,方便后续的建模操作
import numpy as np
import pandas as pd
import re
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
from sklearn.metrics import *
from sklearn.model_selection import train_test_split
import seaborn as sns
这是原文件的截图,可见原文件并没有每一列的元素名称,也没有分列,而是将每一行的元素全塞到一列的前头,这对后续的数据处理并不友好
因此我们要通过一系列的操作将原数据集正确导入dataframe中 ,并且因为该数据集数据多,则也要看是否有缺失值
#读取数据
data = pd.read_csv('housing.csv',header=None)
'''
因为原数据集并未将全部数据都分别放在每一个格子中,所以我们通过一些操作来对数据进行处理,
以便后续的操作
'''
# 提取第一个格子中的数据,并去除空格
va = data.iloc[:, 0].str.strip().values
#利用正则表达式,提取每一行的数字并存储到列表中
result = []
for i in va:
values = re.split(r'\s+', i)
result.append(values)
#将处理好的数据形成一个dataframe
juzhen = np.array(result).reshape(506,14)
df = pd.DataFrame(juzhen,columns=['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE','DIS', 'RAD', 'TAX','PTRATIO','B:1000','lstat','Medv'])
#将数据中的自变量和因变量分开
x = df.iloc[:,:13]
y = df['Medv']
#判断有无nan
print(df.isnull().sum())
这是最后的运行结果:
CRIM ZN INDUS CHAS NOX ... TAX PTRATIO B:1000 lstat Medv
0 0.00632 18.00 2.310 0 0.5380 ... 296.0 15.30 396.90 4.98 24.00
1 0.02731 0.00 7.070 0 0.4690 ... 242.0 17.80 396.90 9.14 21.60
2 0.02729 0.00 7.070 0 0.4690 ... 242.0 17.80 392.83 4.03 34.70
3 0.03237 0.00 2.180 0 0.4580 ... 222.0 18.70 394.63 2.94 33.40
4 0.06905 0.00 2.180 0 0.4580 ... 222.0 18.70 396.90 5.33 36.20
.. ... ... ... ... ... ... ... ... ... ... ...
501 0.06263 0.00 11.930 0 0.5730 ... 273.0 21.00 391.99 9.67 22.40
502 0.04527 0.00 11.930 0 0.5730 ... 273.0 21.00 396.90 9.08 20.60
503 0.06076 0.00 11.930 0 0.5730 ... 273.0 21.00 396.90 5.64 23.90
504 0.10959 0.00 11.930 0 0.5730 ... 273.0 21.00 393.45 6.48 22.00
505 0.04741 0.00 11.930 0 0.5730 ... 273.0 21.00 396.90 7.88 11.90
CRIM 0
ZN 0
INDUS 0
CHAS 0
NOX 0
RM 0
AGE 0
DIS 0
RAD 0
TAX 0
PTRATIO 0
B:1000 0
lstat 0
Medv 0
dtype: int64
因为是预测类问题,我们肯定首先会想清楚这13个变量与最后的房价会有什么样的关系,还有到底是分类还是回归
我这里认为:首先因变量房价这个数据它是一个个连续的数值,也就意味着它是一个定量变量
而分类问题处理的一般是定类变量,比如判断是香蕉还是苹果
并且该数据集也是让我们去预测一个连续的房价值,因此 我们可以判断这是一个回归类问题
接着我们进行机器学习的第二步:数据可视化
既然已经判断了他是回归类问题,那我们就会想知道具体各个变量与y的关系
于是我们打算画出各特征之间的关系热力图
plt.figure(figsize=(10, 8))
correlation_matrix = df.corr()
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm')
plt.show()
运行结果如下图,
可以看出RM,lstat,INDUS,PTRATIO都是与Medv的相关性比较大的特征
但是我觉得没必要因此去只提取这几个特征而忽略其他特征去做模型,因为我觉得其他特征相关性虽然小,但还是不可忽略
数据处理和简单分析已经结束,
那么接下来就是开始分测试集和训练集并开始训练模型了(线性规划)
首先我们先采用最简单的线性回归模型,并利用预测值进行模型评估
x_train,x_test,y_train,y_test = train_test_split(x, y, test_size=0.5, random_state=1)
# 模型训练
xunlian = LinearRegression()
xunlian.fit(x_train,y_train)
#模型评估 MAE平均绝对误差,MSE均方误差,MSLE,r方(决定系数),RMSE
y_pred = xunlian.predict(x_test)
MAE = mean_absolute_error(y_test, y_pred)
MSE = mean_squared_error(y_test, y_pred)
MSLE = mean_squared_log_error(y_test, y_pred)
r2 = r2_score(y_test,y_pred)
rmse = root_mean_squared_error(y_test,y_pred)
print(f'均方根误差:{rmse},均方误差:{MSE},均方对数误差:{MSLE},决定系数:{r2},平均绝对误差:{MAE}')
print(f'Score: {xunlian.score(x_test,y_test) * 100}')
运行结果,得分有74分左右,效果一般
'''
均方根误差:4.779046666296583,均方误差:22.83928703864049,均方对数误差:0.047766987842445215,决定系数:0.7397314185094656,平均绝对误差:3.3374263091091465
Score: 73.97314185094656
'''
结果图像化
然后再用一个预测数据与测试数据的对比图和残差图来直观的感受一下:
#残差图
plt.scatter(y_pred, y_test2-y_pred)
plt.axhline(y=0, color='r', linestyle='--')
plt.xlabel('预测值')
plt.ylabel('残差')
plt.title('线性回归残差图')
plt.show()
#对比图
plt.figure(figsize=(15, 5))
plt.plot(range(len(y_test2)), y_test2, 'r', label='测试数据')
plt.plot(range(len(y_pred)), y_pred, 'b', label='预测数据')
plt.legend()
plt.show()
这里要注意,在进行画图的时候,要注意投喂给matplotib的数据需要是列表,不能是pd的Dataframe,不然就会出现这样的情况
原因是因为测试数据的格式不正确,如下图,y_test依旧是dataframe格式的,我们应该将其转换为一个列表
像下图这样,这样才能正确的被描到图像上
于是乎我们就需要对我们的测试值进行一点调整(预测值不用调整,因为他本身得到的就是列表形式)
def turn_num(list):
for i in range(len(list)):
list[i] = float(list[i])
return list
y_test1 = np.array(y_test)
y_test2 = turn_num(y_test1)
最后的y_test2就是我们所需要的最终值。
最后的图片就是下面这样
进行到这里,我们的线性回归就基本结束了。
那接下来我们再来试试结合特征工程,利用PCA降维,降维成三个主成分来进行线性回归
首先先对数据进行标准化(这里直接导包),并分出测试集和训练集
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
y_df = pd.DataFrame(y).T
#数据标准化
x_1 = scaler.fit_transform(x)
y_1 = scaler.fit_transform(y_df)
x_train_1,x_test_1,y_train_1,y_test_1 = train_test_split(x, y, test_size=0.5, random_state=1)
from sklearn.decomposition import PCA # 加载PCA算法包
pca = PCA(n_components=3)
reduced_x_train = pca.fit_transform(x_train_1)
reduced_x_test = pca.fit_transform(x_test_1)
# print(reduced_x_test)
print(pca.explained_variance_ratio_)
##结果为(0.800,0.169,0.020)
这里得到的三个主成分已经涵盖了百分之九十八的信息了,可用于建模
然后再重新按刚才线性回归的操作再进行一遍,得到下面的结果,可看出拟合程度并不好
'''
均方根误差:8.107199550694645,均方误差:65.72668455478345,均方对数误差:0.08657486772800697,决定系数:0.25100153405806214,平均绝对误差:5.322076249923279
Score:25.100153405806214
'''
我猜测可能是因为由于pca将一些数据特征给吞并,导致降维后的数据反而没能展示原有数据的特征,所以导致拟合不理想的结果。
接下来我们采用其他建模方法去拟合
一.随机森林回归
(变量名称可能与上一个不同)
senlin = RandomForestRegressor(n_estimators=200)
senlin.fit(x_train_1,y_train_1)
y_pred_1 = senlin.predict(x_test_1)
# print(y_pred_1)
MAE = mean_absolute_error(y_test_1, y_pred_1)
MSE = mean_squared_error(y_test_1, y_pred_1)
MSLE = mean_squared_log_error(y_test_1, y_pred_1)
r2 = r2_score(y_test_1,y_pred_1)
rmse = root_mean_squared_error(y_test_1,y_pred_1)
print(f'均方根误差:{rmse},均方误差:{MSE},均方对数误差:{MSLE},决定系数:{r2},平均绝对误差:{MAE}')
print(senlin.score(x_test_1,y_test_1))
'''
均方根误差:3.452199457429062,均方误差:11.91768109387351,均方对数误差:0.02258878903877538,决定系数:0.8641902460566626,平均绝对误差:2.4289308300395245
0.8641902460566626
'''
残差图和拟合图
'''
pca降维后数据,由于通过数据降维,致使某些元素缺失,使应用降维后数据的模型拟合程度并不高
最后的相关的评价指标也同样不理想
均方根误差:8.069074625072432,均方误差:65.1099653049878,均方对数误差:0.08610697142868642,决定系数:0.2580294524011637,平均绝对误差:5.284226285990871
Score:25.802945240116372
还有未标准化的数据得到的结果;
均方根误差:3.41476675631001,均方误差:11.660631999999985,均方对数误差:0.022136128390585378,决定系数:0.8671194882402169,平均绝对误差:2.40382608695652
Score: 0.8671194882402169、
与标准化后的指标相差不大,可以忽略
'''
由此可见,除去pca降维的数据,随机森林的拟合程度还是比较理想的。
二. 决策树回归
这里我们同样采用标准化数据
from sklearn import tree
clf = tree.DecisionTreeRegressor(max_depth=5) # 实例化
clf = clf.fit(x_train, y_train) # 训练
y_pre = clf.predict(x_test)
##模型评价
MAE = mean_absolute_error(y_test, y_pre)
MSE = mean_squared_error(y_test, y_pre)
MSLE = mean_squared_log_error(y_test, y_pre)
r2 = r2_score(y_test,y_pre)
rmse = root_mean_squared_error(y_test,y_pre)
print(f'均方根误差:{rmse},均方误差:{MSE},均方对数误差:{MSLE},决定系数:{r2},平均绝对误差:{MAE}')
print(f'Score: {clf.score(x_test,y_test)}')
'''
均方根误差:4.4694829164581735,均方误差:19.976277540511457,均方对数误差:0.04370028389881609,决定系数:0.7723572802367292,平均绝对误差:3.185784974248413
0.7723572802367292
'''
拟合图像和残差图
结果可知相较于随机森林,该模型的拟合程度还是没那么优良的,
因为随机森林是由一个个决策树来组成的,所探寻的深度肯定更深,拟合性也肯定更好。
三.支持向量机回归
from sklearn import ensemble
clf = ensemble.GradientBoostingRegressor(n_estimators=500, max_depth= 4, min_samples_split= 2,learning_rate= 0.01, loss='squared_error')
clf.fit(x_train, y_train)
y_pre=clf.predict(x_test) #预测值
MAE = mean_absolute_error(y_test, y_pre)
MSE = mean_squared_error(y_test, y_pre)
MSLE = mean_squared_log_error(y_test, y_pre)
r2 = r2_score(y_test,y_pre)
rmse = root_mean_squared_error(y_test,y_pre)
print(f'均方根误差:{rmse},均方误差:{MSE},均方对数误差:{MSLE},决定系数:{r2},平均绝对误差:{MAE}')
print(f'Score: {clf.score(x_test,y_test)}')
'''
均方根误差:5.05747553017549,均方误差:25.57805873832386,均方对数误差:0.06501335604791296,决定系数:0.7085213275772468,平均绝对误差:3.2622484348573297
Score: 0.7085213275772468
'''
结果图像
四.梯度升级
from sklearn import ensemble
gb = ensemble.GradientBoostingRegressor()
gb.fit(x_train_1, y_train_1)
y_pre=gb.predict(x_test_1)
##模型评价
MAE = mean_absolute_error(y_test, y_pre)
MSE = mean_squared_error(y_test, y_pre)
MSLE = mean_squared_log_error(y_test, y_pre)
r2 = r2_score(y_test,y_pre)
rmse = root_mean_squared_error(y_test,y_pre)
print(f'均方根误差:{rmse},均方误差:{MSE},均方对数误差:{MSLE},决定系数:{r2},平均绝对误差:{MAE}')
print(f'Score: {gb.score(x_test,y_test)}')
'''
均方根误差:3.2727693114783007,均方误差:10.711018966154151,均方对数误差:0.022921529904383616,决定系数:0.8779409485102257,平均绝对误差:2.278362699775118
Score: 0.8779409485102257
'''
拟合图像和残差图
拟合程度在上述几个模型中得到最高的分数,可见该模型的拟合程度是非常不错的了。
总结
在目前试过的五种模型里,梯度提升算是拟合的最好的一个模型了,随机森林拟合的也很不错。
然后在这些回归型问题中,大多数的模型都能通过sklearn来调包运行,都很方便
所以在机器学习的过程中,最重要还是对数据进行一定的处理,和分析。并决定用什么模型。