K近邻模型

K近邻模型

K近邻模型既可以预测分类问题,也可以用于连续性变量预测问题。
模型的本质就是寻找k个最近样本,然后基于最近样本做“预测”。
对于离散型的因变量来说,从k个最近的已知类别样本中挑选出频率最高的类别用于未知样本的判断。
对于连续型的因变量来说,则是将k个最近的已知样本均值用作未知样本的预测。

模型执⾏步骤

1. 确定未知样本近邻的个数k值。
2. 根据某种度量样本间相似度的指标(如欧式距离)将每一个未知类别样本的最近k个已知样本搜索出来,形成一个个簇。
3. 对搜索出来的已知样本进行投票,将各簇下类别最多的分类作用于未知样本点的预测。

K值的选择

不同的k值对于模型的预测准确性会有比较大的影响。
如果k值过于偏小,可能会导致模型的过拟合;反之可能使模型欠拟合。

方法一:
设置k近邻样本的投票权重。
使⽤KNN算法进⾏分类或预测时设置的k值⽐较⼤,担⼼模型发⽣⽋拟合的现象。
⼀个简单有效的处理办法就是设置近邻样本的投票权重。
如果已知样本距离未知样本⽐较远,则对应的权重就设置得低⼀些,否则权重就⾼⼀些。
通常可以将权重设置为距离的倒数。

方法二:
采用多重交叉验证法。
该方法是目前比较流行的方案,其核心就是将k取不同的值,
然后在每种值下执行m重交叉验证,最后选出平均误差最小的k值。

欧式距离

两点间的直线(最短)距离

曼哈顿距离

两个点在标准坐标系上的绝对轴距总和

函数说明

neighbors.KNeighborsClassifier(n_neighbors=5, weights='uniform',
p=2, metric='minkowski',)

n_neighbors:⽤于指定近邻样本个数K,默认为5
weights:⽤于指定近邻样本的投票权重,默认为'uniform',表示所有近邻样本的投票权重⼀样;如果
为'distance',则表示投票权重与距离成反⽐,即近邻样本与未知类别的样本点距离越远,权重越⼩,
反之,权重越⼤
metric:⽤于指定距离的度量指标,默认为闵可夫斯基距离
p:当参数metric为闵可夫斯基距离时,p=1,表示计算点之间的曼哈顿距离;p=2,表示计算点之间
的欧⽒距离;该参数的默认值为2

代码演示

# 一:
# 导入第三方包
import pandas as pd
# 导⼊数据
Knowledge = pd.read_excel(r'Knowledge.xlsx')

# 构造训练集与测试集
# 导入第三方包
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)

# 导入第三方包
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()

# 导入第三方包
from sklearn import metrics

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

# 导入第三方包
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()

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

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


# 二:
# 读⼊数据
ccpp = pd.read_excel(r'CCPP.xlsx')

# 统一量纲
# 导入第三方包
from sklearn.preprocessing import minmax_scale
# 对所有⾃变量数据做标准化处理
predictors = ccpp.columns[:-1]
X = minmax_scale(ccpp[predictors])

# 将数据集拆分为训练集与测试集
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_reg = neighbors.KNeighborsRegressor(n_neighbors = int(K[arg_min]), weights = 'distance')
# 模型拟合
knn_reg.fit(X_train, y_train)
# 模型在测试集上的预测
predict = knn_reg.predict(X_test)
# 计算MSE值
metrics.mean_squared_error(y_test, predict)

# 对⽐真实值和实际值(前10组数据)
pd.DataFrame({'Real':y_test,'Predict':predict}, 
columns=['Real','Predict']).head(10)
上一篇:INNODB自增主键的一些问题


下一篇:机器学习学习笔记之——监督学习之 k-NN 算法