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份,第一份作为验证集,其余作为训练集,而后再把第二份作为验证集,其余部分作为训练集……以此类推,直到全部验证完毕,因此省去了拆分数据集的步骤。