深入浅出Python量化交易实战
上QQ阅读APP看书,第一时间看更新

3.2.3 KNN算法用于回归

下面我们就来给小瓦展示KNN算法在回归任务中的应用。

1.载入数据集并查看

这里依旧使用scikit-learn内置的数据集来给小瓦进行讲解。说到回归任务,我们自然会想到波士顿房价数据集。该数据集中有506个样本,每个样本有13个特征,以及对应的价格(target)。下面我们载入数据集并对其进行初步的了解。

#载入波士顿房价数据集导入工具
from sklearn.datasets import load_boston
#将数据导入
boston = load_boston()
#查看数据集的键名
boston.keys()

运行代码,会得到以下结果:

dict_keys(['data', 'target', 'feature_names', 'DESCR', 'filename'])

【结果分析】从代码运行结果可以看出,数据集中存储了5个键,这里我们重点关注target(房屋的售价)及feature_names(房屋的特征)。也就是说,我们需要训练模型,让它学习房屋特征和售价的关系,并且可以自动预测出新房屋的售价。

下面来看一下数据中存储的特征都有哪些,输入代码如下:

#查看样本的特征名称
boston.feature_names

运行代码,会得到以下结果:

array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
'TAX', 'PTRATIO', 'B', 'LSTAT'], dtype='<U7')

【结果分析】从代码运行结果可以看到,程序返回了样本全部的特征名称,包括房间数量RM、房龄AGE等共计13个。因为这里只是进行回归分析的演示,所以我们不展开讲解这些特征具体代表什么。感兴趣的读者可以自行查看scikit-learn官方文件进行深入了解。

如果读者朋友希望继续了解房屋的价格是什么样子,可以使用下面这行代码来查看一下:

#选取前十套房屋,查看售价
boston.target[:10]

运行代码,可以看到程序返回的前10套房屋售价如下:

array([24. , 21.6, 34.7, 33.4, 36.2, 28.7, 22.9, 27.1, 16.5, 18.9])

接下来重复进行类似分类任务的步骤,将数据集拆分为训练集和验证集。

2.拆分数据集并训练模型

与分类任务一样,在回归任务中,我们也要使用训练集来训练模型,并使用验证集来验证模型的性能。下面来进行数据集的拆分,输入代码如下。

#将样本特征和售价赋值给X,y
X, y = boston.data, boston.target
#使用train_test_split拆分为训练集和验证集
X_train, X_test, y_train, y_test =\
train_test_split(X, y)
#查看拆分的结果
X_train.shape

运行代码,会得到如下结果:

(379, 13)

【结果分析】如果读者朋友也得到了这个结果,就说明你的数据集拆分成功。训练集中有379个样本,其余127个样本进入了验证集。

下面开始模型的训练,输入代码如下:

#导入KNN回归算法
from sklearn.neighbors import KNeighborsRegressor
#创建一个实例,参数保持默认设置
knn_reg = KNeighborsRegressor()
#拟合训练集数据
knn_reg.fit(X_train, y_train)
#查看模型在训练集和验证集的性能表现
print('训练集准确率:%.2f'%knn_reg.score(X_train, y_train))
print('验证集准确率:%.2f'%knn_reg.score(X_test, y_test))

运行代码,会得到以下结果:

训练集准确率:0.71
验证集准确率:0.50

【结果分析】从上面的代码运行结果可以看到,缺省参数的KNN回归模型在该数据集中的性能表现差强人意,在训练集中的准确率只有71%,而在验证集中则更加糟糕,只有50%。这说明模型出现了欠拟合的问题,我们需要对数据集进行处理,或者对模型进行调优。

3.模型评估的不同方法和改进

到这里,相信读者朋友们和小瓦一样,发现了这样一个事情:不论是在分类模型中,还是回归模型中,我们都使用了.score( )方法来评估模型的性能。然而,在两种模型中,.score( )方法所进行的计算是不一样的。在分类模型中,.score( )返回的是模型预测的准确率(accuracy),其计算公式为

在上面这个公式中,TP(True Positive)表示模型预测正确的正样本数量;TN(True Negative)表示模型预测正确的负样本数量;FP(False Positive)表示原本是负样本,却被模型预测为正样本的数量,也就是我们平时说的“假阳性”;FN(False Negative)表示原本是正样本,却被模型预测为负样本的数量,也就是“假阴性”。TP、FP、TN、FN的和就是所有的样本数量。也就是说,分类模型的准确率是模型预测正确的样本数量,除以全部参与预测的样本数量。当然,除了准确率之外,我们还可以用Precision、Recall、F1 score等方法来对分类模型进行性能评估,这里暂时不展开讲解。

在回归任务中,.score( )方法返回的是模型的R2。对于小瓦来说,这个概念有些陌生。R2是描述模型预测数值与真实值差距的指标,它的计算公式为

在这个公式中,代表模型对样本的估计值,y可代表的是样本真实值的均值。也就是说,R2是样本真实值减模型估计值,再进行平方并求和,除以样本真实值减样本平均值的平方和,最后用1减去这个结果。因此R2取值为0~1,并且越接近1,说明模型的性能越好。

除了R2之外,回归模型还可以用均方误差(Mean Squared Error,MSE)、绝对中位差(Median Absolute Error,MAE)等指标来进行评估。如果有需要,我们也会在后面做进一步的讲解。

前面说了,缺省参数的KNN模型在波士顿房价预测这个任务中的表现并不理想。下面我们尝试对KNN回归的参数进行调整,看是否可以改进模型的性能。与分类模型一样,我们先使用网格搜索来寻找模型的最优参数。输入代码如下:

运行代码,会得到以下结果:

{'n_neighbors': 10}

【结果分析】从上面的代码运行结果可以看到,KNN回归模型的最佳n_neighbors参数是10,也就是说,当n_neighbors取10时,模型的R2最高。

现在来看一下当n_neighbors取10时,模型的R2是多少。输入代码如下:

#查看最佳参数对应的最佳模型R2
cv.best_score_

运行代码,会得到以下结果:

0.98

【结果分析】从代码运行结果可以看到,当我们设置KNN回归模型的n_neighbors参数为10时,模型的R2提高到了0.98,可以说在性能方面有了显著的提升。

注意:在使用网格搜索时,我们没有手动将数据集拆分为训练集和验证集。这是因为网格搜索内置了交叉验证(cross validation)法。在网格搜索中,我们设置cv参数为5,也就是说,交叉验证会将数据分成5份,第一份作为验证集,其余作为训练集,而后再把第二份作为验证集,其余部分作为训练集……以此类推,直到全部验证完毕,因此省去了拆分数据集的步骤。