kNN模型

KNN算法是一个非常优秀的数据挖掘模型,既可以解决离散型因变量的分类问题,也可以处理连续型因变量的预测问题,而且该算法对数据的分布特征没有任何要求。

Python中的sklearn模块提供了有关KNN算法实现分类和预测的功能,该功能存在于子模块neighbors中,对于分类问题,需要调KNeighborsClassifier“类”,而对于预测问题,则需要调用KNeighborsRegressor“类”。

函数

neighbors.KNeighborsClassifier(n_neighbors=5, weights='uniform', algorithm='auto', 
	leaf_size=30, p=2, metric='minkowski', 
	metric_params=None, n_jobs=1)

neighbors.KNeighborsRegressor(n_neighbors=5, weights='uniform', algorithm='auto', 
	leaf_size=30, p=2, metric='minkowski', 
	metric_params=None, n_jobs=1)

n_neighbors:用于指定近邻样本个数K,默认为5。

weights:用于指定近邻样本的投票权重,默认为'uniform',表示所有近邻样本的投票权重一样;如果为'distance',则表示投票权重与距离成反比,即近邻样本与未知类别的样本点距离越远,权重越小,反之,权重越大。

algorithm:用于指定近邻样本的搜寻算法,如果为'ball_tree',则表示使用球树搜寻法寻找近邻样本;如果为'kd_tree',则表示使用KD树搜寻法寻找近邻样本;如果为'brute',则表示使用暴力搜寻法寻找近邻样本。默认为'auto',表示KNN算法会根据数据特征自动选择最佳的搜寻算法。

leaf_size:用于指定球树或KD树叶子节点所包含的最小样本量,它用于控制树的生长条件,会影响树的查询速度,默认为30。

metric:用于指定距离的度量指标,默认为闵可夫斯基距离。

p:当参数metric为闵可夫斯基距离时,p=1,表示计算点之间的曼哈顿距离;p=2,表示计算点之间的欧氏距离;该参数的默认值为2。

metric_params:为metric参数所对应的距离指标添加关键字参数。

n_jobs:用于设置KNN算法并行计算所需的CPU数量,默认为1表示仅使用1个CPU运行算法,即不使用并行运算功能。

分类问题的解决

使用Knowledge数据集作为演示,该数据集来自于UCI主页
(http://archive.ics.uci.edu/ml/datasets.html)。数据集一共包含403个观测和6个变量

# 导入第三方包
import pandas as pd
# 导入数据
Knowledge = pd.read_excel(r'Knowledge.xlsx')
# 返回前5行数据
Knowledge.head()

out:
	STG	SCG	STR	LPR	PEG	UNS
0	0.00	0.00	0.00	0.00	0.00	Very Low
1	0.08	0.08	0.10	0.24	0.90	High
2	0.06	0.06	0.05	0.25	0.33	Low
3	0.10	0.10	0.15	0.65	0.30	Middle
4	0.08	0.08	0.08	0.98	0.24	Low
# 构造训练集和测试集
# 导入第三方模块
from sklearn import model_selection
# 将数据集拆分为训练集和测试集
predictors = Knowledge.columns[:-1]
X_train, X_test, y_train, y_test = model_selection.train_test_split(Knowledge[predictors], Knowledge.UNS, 
                                                                    test_size = 0.25, random_state = 1234)

一切就绪以后,按理应该构造KNN的分类模型,但是前提得指定一个合理的近邻个数k,因为模型非常容易受到该值的影响。虽然KNeighborsClassifier“类”提供了默认的近邻个数5,但并不代表该值就是合理的,所以需要利用多重交叉验证的方法,获取符合数据的理想k值

# 导入第三方模块
import numpy as np
from sklearn import neighbors
import matplotlib.pyplot as plt

# 设置待测试的不同k值
K = np.arange(1,np.ceil(np.log2(Knowledge.shape[0]))).astype(int)
# 构建空的列表,用于存储平均准确率
accuracy = []
for k in K:
    # 使用10重交叉验证的方法,比对每一个k值下KNN模型的预测准确率
    cv_result = model_selection.cross_val_score(neighbors.KNeighborsClassifier(n_neighbors = k, weights = 'distance'), 
                                                X_train, y_train, cv = 10, scoring='accuracy')
    accuracy.append(cv_result.mean())

# 从k个平均准确率中挑选出最大值所对应的下标    
arg_max = np.array(accuracy).argmax()
# 中文和负号的正常显示
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 绘制不同K值与平均预测准确率之间的折线图
plt.plot(K, accuracy)
# 添加点图
plt.scatter(K, accuracy)
# 添加文字说明
plt.text(K[arg_max], accuracy[arg_max], '最佳k值为%s' %int(K[arg_max]))
# 显示图形
plt.show()

经过10重交叉验证的运算,确定最佳的近邻个数为6个。接下来,利用这
个最佳的k值对训练数据集进行建模,并将建好的模型应用在测试数据集上
kNN模型_第1张图片

# 导入第三方模块
from sklearn import metrics

# 重新构建模型,并将最佳的近邻个数设置为6
knn_class = neighbors.KNeighborsClassifier(n_neighbors = 6, weights = 'distance')
# 模型拟合
knn_class.fit(X_train, y_train)
# 模型在测试数据集上的预测
predict = knn_class.predict(X_test)
# 构建混淆矩阵
cm = pd.crosstab(predict,y_test)
cm



       UNS	High	Low	Middle	Very Low
row_0				
High	29	0	0	0
Low	    0	34	3	5
Middle	1	0	23	0
Very Low	0	0	0	6
# 导入第三方模块
import seaborn as sns

# 将混淆矩阵构造成数据框,并加上字段名和行名称,用于行或列的含义说明
cm = pd.DataFrame(cm)
# 绘制热力图
sns.heatmap(cm, annot = True,cmap = 'GnBu')
# 添加x轴和y轴的标签
plt.xlabel(' Real Lable')
plt.ylabel(' Predict Lable')
# 图形显示
plt.show()

kNN模型_第2张图片
热力图中的每一行代表真实的样本类别,每一列代表预测的样本类别,
区块颜色越深对应的数值越高。很明显,主对角线上的颜色都是比较深的,说明绝大多数样本是被正确分类的。以图中的第一列(High)为例,实际为High的学生有30个,预测为High的学生为29个,说明High类别的覆盖率为29/30,同理也可查看其他列的预测覆盖率。如果想根据如上的混淆矩阵,得到模型在测试集上的预测准确率,可以输入下方的代码

# 模型整体的预测准确率
# metrics.scorer.accuracy_score(y_test, predict)
metrics._scorer.accuracy_score(y_test, predict)

模型的预测准确率为91.09%。准确率的计算公式为:混淆矩阵中主对角线
数字之和与所有数字之和的商。遗憾的是,该指标只能衡量模型的整体预测效果,却无法对比每个类别的预测精度、覆盖率等信息。如需计算各类别的预测效果,可以使用下方的代码

# 分类模型的评估报告
print(metrics.classification_report(y_test, predict))

out:
              precision    recall  f1-score   support

        High       1.00      0.97      0.98        30
         Low       0.81      1.00      0.89        34
      Middle       0.96      0.88      0.92        26
    Very Low       1.00      0.55      0.71        11

    accuracy                           0.91       101
   macro avg       0.94      0.85      0.88       101
weighted avg       0.93      0.91      0.91       101

前四行代表因变量y中的各个类别值,最后一行为各指标的综合水平;第
一列precision表示模型的预测精度,计算公式为“预测正确的类别个数/该类别预测的所有个数”;第二列recall表示模型的预测覆盖率,计算公式为“预测正确的类别个数/该类别实际的所有个数”;第三列f1-score是对precision和recall的加权结果;第四列为类别实际的样本个数。

预测问题的解决

对于预测问题的实战,将使用CCPP数据集作为演示,该数据集涉及高炉煤气联合循环发电的几个重要指标

# 读入数据
ccpp = pd.read_excel(r'CCPP.xlsx')
ccpp.head()

out:
	
		
	AT		V		AP			RH		PE
0	14.96	41.76	1024.07		73.17	463.26
1	25.18	62.96	1020.04		59.08	444.37
2	5.11	39.40	1012.16		92.14	488.56
3	20.86	57.32	1010.24		76.64	446.48
4	10.82	37.50	1009.23		96.62	473.90

前4个变量为自变量,AT表示高炉的温度、V表示炉内的压力、AP表示高炉
的相对湿度、RH表示高炉的排气量;最后一列为连续型的因变量,表示高炉的发电量。该数据集一共包含9 568条观测,由于4个自变量的量纲不一致,因此在使用KNN模型进行预测之前,需要对其做标准化处理:

# 返回数据集的行数与列数
ccpp.shape

(9568, 5)
# 导入第三方包
from sklearn.preprocessing import minmax_scale
# 对所有自变量数据作标准化处理
predictors = ccpp.columns[:-1]
X = minmax_scale(ccpp[predictors])

将数据集拆分为两部分,分别用于用户模型的构建和模型的测试。使用训练
集构建KNN模型之前,必须指定一个合理的近邻个数k值。这里仍然使用10重交叉验证的方法,所不同的是,在验证过程中,模型好坏的衡量指标不再是准确率,而是MSE(均方误差)

# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, ccpp.PE, 
                                                                    test_size = 0.25, random_state = 1234)
# 设置待测试的不同k值
K = np.arange(1,np.ceil(np.log2(ccpp.shape[0]))).astype(int)
# 构建空的列表,用于存储平均MSE
mse = []
for k in K:
    # 使用10重交叉验证的方法,比对每一个k值下KNN模型的计算MSE
    cv_result = model_selection.cross_val_score(neighbors.KNeighborsRegressor(n_neighbors = k, weights = 'distance'), 
                                                X_train, y_train, cv = 10, scoring='neg_mean_squared_error')
    mse.append((-1*cv_result).mean())

# 从k个平均MSE中挑选出最小值所对应的下标  
arg_min = np.array(mse).argmin()
# 绘制不同K值与平均MSE之间的折线图
plt.plot(K, mse)
# 添加点图
plt.scatter(K, mse)
# 添加文字说明
plt.text(K[arg_min], mse[arg_min] + 0.5, '最佳k值为%s' %int(K[arg_min]))
# 显示图形
plt.show()

kNN模型_第3张图片

# 重新构建模型,并将最佳的近邻个数设置为7
knn_reg = neighbors.KNeighborsRegressor(n_neighbors = 7, weights = 'distance')
# 模型拟合
knn_reg.fit(X_train, y_train)
# 模型在测试集上的预测
predict = knn_reg.predict(X_test)
# 计算MSE值
metrics.mean_squared_error(y_test, predict)

对于连续因变量的预测问题来说,通常使用MSE或RMSE(均方误差根)评
估模型好坏,该值越小,说明预测值与真实值越接近。单看上面计算所得的12.81可能没有什么感觉,这里可以对比测试集中的真实数据和预测数据,查看两者之间的差异,不妨取出各自的前10行用于比较

# 对比真实值和实际值
pd.DataFrame({'Real':y_test,'Predict':predict}, columns=['Real','Predict']).head(10)


		Real	Predict
2620	435.68	437.677598
6998	442.90	443.101594
2857	449.01	448.758681
6510	449.75	445.560046
5368	455.20	453.010541
3486	453.49	455.462162
6251	479.14	476.543251
5548	446.71	445.576955
2266	429.80	430.824836
5615	474.40	474.400000

KNN算法与第10章所介绍的决策树非常类似,在建模时都对数据没有什
么特殊要求,这里不妨对比两个模型在CCPP数据集上的表现

# 导入第三方模块
from sklearn import tree

# 预设各参数的不同选项值
max_depth = [19,21,23,25,27]
min_samples_split = [2,4,6,8]
min_samples_leaf = [2,4,8,10,12]
parameters = {'max_depth':max_depth, 'min_samples_split':min_samples_split, 'min_samples_leaf':min_samples_leaf}
# 网格搜索法,测试不同的参数值
grid_dtreg = model_selection.GridSearchCV(estimator = tree.DecisionTreeRegressor(), param_grid = parameters, cv=10)
# 模型拟合
grid_dtreg.fit(X_train, y_train)
# 返回最佳组合的参数值
grid_dtreg.best_params_
# 构建用于回归的决策树
CART_Reg = tree.DecisionTreeRegressor(max_depth = 21, min_samples_leaf = 10, min_samples_split = 6)
# 回归树拟合
CART_Reg.fit(X_train, y_train)
# 模型在测试集上的预测
pred = CART_Reg.predict(X_test)
# 计算衡量模型好坏的MSE值
metrics.mean_squared_error(y_test, pred)

由于决策树涉及的预剪枝参数比较多,故选择网格搜索法确定最佳的参数,同样经过10重交叉验证后,得到最佳的参数组合。接下来利用如上结果所示的参数构造预测回归树,并计算测试集上的MSE值,利用预测回归树模型对CCPP数据集进行建模,在测试集上计算得到的MSE值为16.14。该值要大于KNN模型的MSE值,说明决策树模型在CCPP数据集上的拟合效果并没有KNN模型理想。

你可能感兴趣的:(机器学习,python,机器学习,数据挖掘)