一、代码实现
'''
功能:使用鸢尾花卉数据集和 K 折交叉验证,选取最优的 KNN 算法参数 k
'''
# 导包
from sklearn import datasets
import numpy as np
import pandas as pd
from sklearn import model_selection
from sklearn import neighbors
import math
from sklearn import metrics
import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 使用 k 折交叉验证,选取最优的参数
def choose_bestK(myData, data_train, label_train):
K = np.arange(1, math.floor(math.sqrt(myData.shape[0])))
scores = []
for k in K:
knn = neighbors.KNeighborsClassifier(n_neighbors=k)
scores.append(model_selection.cross_val_score(knn, data_train, label_train, cv=10).mean())
bestK_ind = np.array(scores).argmax() # 最优的 k 参数
# 对不同的 k 值得分可视化
plt.figure()
plt.plot(K, scores)
plt.scatter(K, scores)
plt.text(K[bestK_ind], scores[bestK_ind], '最佳k值为%d' %int(K[bestK_ind]))
# plt.show()
return K, scores, bestK_ind
# 使用最优 k 值进行模型训练及预测,并构建混淆矩阵
def model_train_knn(bestK, x_train, y_train, x_test, y_test):
knn = neighbors.KNeighborsClassifier(n_neighbors=bestK)
knn.fit(x_train, y_train)
y_test_pre = knn.predict(x_test)
# 构建混淆矩阵
tmp = []
for i in range(len(y_test)):
tmp.append(y_test.values[i][0])
tmp = np.array(tmp)
cm = pd.crosstab(y_test_pre, tmp) # pd.crosstab()的输入数据类型应该是 narray!
return cm, y_test_pre
# 构造混淆矩阵热度图
def Confusion_matrix_hp(cm):
# 将混淆矩阵构造成数据框,并加上字段名和行名称,用于行或列的含义说明
cm = pd.DataFrame(cm)
# 绘制热力图
sns.heatmap(cm, annot=True, cmap='GnBu')
plt.xlabel('Real Label')
plt.ylabel('Predict Label')
# plt.show()
# 模型评价和报告输出
def scoreAndReport(y_test, y_test_pre):
y_test_ndarray = y_test.values # dataframe 转成 ndarray
y_test_ndarray = y_test_ndarray.ravel() # 将 ndarray 拉成一维数组
accur = metrics.accuracy_score(y_test_ndarray, y_test_pre)
report = metrics.classification_report(y_test_ndarray, y_test_pre)
# precision = metrics.precision_score(y_test_ndarray, y_test_pre) # 该指标多分类不可用
# recall = metrics.recall_score(y_test_ndarray, y_test_pre) # 该指标多分类不可用
# f1_score = metrics.f1_score(y_test_ndarray, y_test_pre) # 该指标多分类不可用
# AUC = metrics.auc(y_test_ndarray, y_test_pre) # 该指标多分类不可用
# fpr, tpr, thesholds = metrics.roc_curve(y_test_ndarray, y_test_pre) # 该指标多分类不可用
# metrics.auc(fpr, tpr) # 该指标多分类不可用
return accur, report
if __name__ == '__main__':
# 导入数据集
dataset = datasets.load_iris()
feaName = dataset.feature_names # 数据集特征名称 >> ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
tarName = dataset.target_names # 数据集标签名称 >> ['setosa' 'versicolor' 'virginica']
myData = pd.DataFrame(data=dataset.data) # 特征数据
labels = pd.DataFrame(data=dataset.target) # 标签
# 划分训练集和测试集
data_train, data_test, label_train, label_test = model_selection.train_test_split(myData, labels, test_size=0.2)
K, scores, bestK_ind = choose_bestK(myData, data_train, label_train)
bestK = K[bestK_ind] # 最优参数k
cm, label_test_pre = model_train_knn(bestK, data_train, label_train, data_test, label_test)
Confusion_matrix_hp(cm)
score, report = scoreAndReport(label_test, label_test_pre)
print(score, '\n', report)
(参考:Python 第三方库Knn算法)
运行结果:
二、知识点
1. numpy 的 argmax 的用法
argmax 返回的是最大数的索引。argmax 有一个参数 axis,默认为0,表示第几维的最大值。
(参考:(Python)numpy的argmax用法)
2. list 和 ndarray 的相互转化
(1)list 转 ndarray:b = np.array(a)
(2)ndarray 转 list:a = b.tolist()
(参考:Python:list和ndarray的互相转化)
3. ravel() 的用法
功能:将数组维度拉成一维数组
a = [[1], [2], [2], [3]]
b = a.ravel() # 该函数不会修改原始 a 的值,所以需要开辟新内存
print(b)
>> [1, 2, 2, 3]
metrics.accuracy_score() 的输入需要是 (n_samples, ),否则会报错。
此时,使用 np.ravel() 函数将数组维度拉成一维,该问题解决。~
(参考:python中ravel()用法)
4. 二分类的评价指标不可直接用于多分类
二分类常见的评价指标:准确率accuracy,精确的precision,召回率recall,f1-score,ROC曲线,AUC等。(详见:【20210914】【机器/深度学习】模型评价指标:精确率、召回率、特异性、敏感性、F1-score、ROC曲线、AUC)
其中只有准确率accuracy 可用于多分类~其他都会报错!常见的多分类评价指标:宏平均 Macro F1,微平均 Micro F1 等。
(参考:二分类和多分类的性能评价指标及python计算)
(参考:多分类f1分数_【评价指标】详解F1-score与多分类MacroF1&MicroF1)
(参考:【评价指标】详解F1-score与多分类F1)
(参考:target is multiclass but average='binary'. please choose another average setting.)
5. k 折交叉验证及 sklearn 中 cross_val_score 的使用
交叉验证可以解决:数据集量不够大的问题、参数调优的问题。
交叉验证主要有三种方式:简单交叉验证(HoldOut检验)、k折交叉验证(k-fold交叉验证)、自助法。
(1)简单交叉验证(HoldOut检验)
原理:将原始数据随机划分成训练集和验证集两个部分。
缺点:数据都只被用了一次,没有被充分利用;在验证集上计算出来的最后的评估指标与原始分组有很大关系。
(2)k-fold交叉验证
原理:将全部样本划分成 k 个大小相等的样本子集;依次遍历这 k 个子集,每次把当前子集作为验证集,其余所有样本作为训练集,进行模型的训练和评估;最终把 k 次评估指标的平均值作为最终的评估指标。
(参考:使用sklearn的cross_val_score进行交叉验证)
(参考:交叉验证以及scikit-learn中的cross_val_score详解)
(参考:为什么cross_val_score返回几个分数?)