分类与回归算法3:KNN

1. KNN简介

KNN最邻近分类算法的实现原理:为了判断未知样本的类别,以所有已知类别的样本作为参照,计算未知样本与所有已知样本的距离,从中选取与未知样本距离最近的K个已知样本,根据少数服从多数的投票法则(majority-voting),将未知样本与K个最邻近样本中所属类别占比较多的归为一类。

由于KNN最邻近分类算法在分类决策时只依据最邻近的一个或者几个样本的类别来决定待分类样本所属的类别,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。

KNN算法的数据处理要点:

  1. 样本的所有特征都要做可比较的量化
    若是样本特征中存在非数值的类型,必须采取手段将其量化为数值。例如样本特征中包含颜色,可通过将颜色转换为灰度值来实现距离计算。
  2. 样本特征要做归一化处理
    样本有多个参数,每一个参数都有自己的定义域和取值范围,他们对距离计算的影响不一样,如取值较大的影响力会盖过取值较小的参数。所以样本参数必须做一些 scale 处理,最简单的方式就是所有特征的数值都采取归一化处置。

2. python实现

2.1 数据准备

import pandas as pd
from sklearn.neighbors import KNeighborsClassifier as KNN
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.model_selection import GridSearchCV
from sklearn import datasets #导入数据集模块
from sklearn.metrics import classification_report   #用于显示主要分类指标的文本报告
import sklearn.metrics as sm #生成混淆矩阵的库
import seaborn as sn  #混淆矩阵可视化的库
import matplotlib.pyplot as plt #画图

#--------------------------------1.加载数据集---------------------------------#
# 导入数据,提取特征变量与目标变量
iris = datasets.load_iris()#加载鸢尾花数据集
X = iris.data #输入特征
#利用映射将分类变量转化为数值
'''插入
Y_mapping = {'XL':3, 'L':2, 'M':1}
df['size'] = df['size'].map(size_mapping)
'''
Y = iris.target #标签(输出特征)

# 划分训练集与测试集
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=123)

2.2 基础模型搭建预测与评估

#--------------------------------2.1 基础模型搭建、预测---------------------------------#

#基础模型搭建
knn1 = KNN(n_neighbors=5)
knn1.fit(X_train, y_train)

# 基础模型预测
y_pred1 = knn1.predict(X_test)

#--------------------------------2.2 基础模型评估---------------------------------#
# 基础模型评估
accuracy = accuracy_score(y_pred1, y_test)
# 或者模型自带函数model.score(X_test,y_test),注意两个函数的参数不一样
print(accuracy)

m = sm.confusion_matrix(y_test, y_pred1) #生成混淆矩阵
print('混淆矩阵为:', m, sep='\n')
ax = sn.heatmap(m, annot=True, fmt='.20g')
ax.set_title('confusion matrix')
ax.set_xlabel('predict')
ax.set_ylabel('true')
plt.show() #混淆矩阵可视化
print("测试集准确率:%s"%knn1.score(X_test,y_test))   #输出测试集准确度
print("分析报告:", classification_report(y_test,y_pred1))#生成分类报告

注意:KNN函数参数说明

'''
KNN函数参数说明:
def KNeighborsClassifier(n_neighbors = 5,
                       weights='uniform',
                       algorithm = '',
                       leaf_size = '30',
                       p = 2,
                       metric = 'minkowski',
                       metric_params = None,
                       n_jobs = None
                       )
1.n_neighbors:这个值就是指 KNN 中的 “K”了。前面说到过,通过调整 K 值,算法会有不同的效果。

2.weights(权重):最普遍的 KNN 算法无论距离如何,权重都一样,但有时候我们想搞点特殊化,比如距离更近的点让它更加重要。这时候就需要 weight 这个参数了,这个参数有三个可选参数的值,决定了如何分配权重。参数选项如下:
· ‘uniform’:不管远近权重都一样,就是最普通的 KNN 算法的形式。
· ‘distance’:权重和距离成反比,距离预测目标越近具有越高的权重。
·  自定义函数:自定义一个函数,根据输入的坐标值返回对应的权重,达到自定义权重的目的。

3.algorithm:在 Sklearn 中,要构建 KNN 模型有三种构建方式:
· 暴力法,就是直接计算距离存储比较的那种方式。
· 使用 Kd 树构建 KNN 模型。
· 使用球树构建。
 其中暴力法适合数据较小的方式,否则效率会比较低。如果数据量比较大一般会选择用 Kd 树构建 KNN 模型,而当 Kd 树也比较慢的时候,则可以试试球树来构建 KNN
 * ‘brute’ :蛮力实现;
* ‘kd_tree’:KD 树实现 KNN;
* ‘ball_tree’:球树实现 KNN ;
* ‘auto’: 默认参数,自动选择合适的方法构建模型。

4.metric:指定距离度量方法,一般都是使用欧式距离。
* ‘euclidean’ :欧式距离;
* ‘manhattan’:曼哈顿距离;
* ‘chebyshev’:切比雪夫距离;
* ‘minkowski’: 闵可夫斯基距离,默认参数。

5.p:和 metric 结合使用,当 metric 参数是 “minkowski” 的时候,p=1 为曼哈顿距离, p=2 为欧式距离。默认为p=2。

6.leaf_size:如果是选择蛮力实现,那么这个值是可以忽略的。当使用 Kd 树或球树,它就是停止建子树的叶子节点数量的阈值。默认30,但如果数据量增多这个参数需要增大,否则速度过慢不说,还容易过拟合。

7.p:和 metric 结合使用,当 metric 参数是 “minkowski” 的时候,p=1 为曼哈顿距离, p=2 为欧式距离。默认为p=2。

'''

2.3 参数调优模型的建立、预测与评估

调优可以使用网格搜索法,也可以手写代码


#--------------------------------3.1 调优模型搭建---------------------------------#
#调优模型建立
parameters = {'n_neighbors':[5,6,7,8,9,10]}
knn2 = KNN()
knn2 = GridSearchCV(knn2, parameters, cv=5)
# 以准确度为基础进行网格搜索,寻找最优参数
knn2.fit(X_train, y_train)
print(knn2.best_params_)
#调优模型预测与评估
Y_pre2=knn2.predict(X_test)#预测测试集

#--------------------------------3.2 调优模型评估 网格搜索法---------------------------------#
m = sm.confusion_matrix(y_test, Y_pre2) #生成混淆矩阵
print('混淆矩阵为:', m, sep='\n')
ax = sn.heatmap(m, annot=True, fmt='.20g')
ax.set_title('confusion matrix')
ax.set_xlabel('predict')
ax.set_ylabel('true')
plt.show() #混淆矩阵可视化
print("调优后测试集准确率:%s"%knn2.score(X_test, y_test))   #输出测试集准确度
print("调优后分析报告:", classification_report(y_test, Y_pre2))#生成分类报告


'''
人工确定K的方法:

# talk is cheap show me the code

# 导入算法包
from random import choice
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import KFold, StratifiedKFold

# 预设进行10段交叉验证
N = 10

#采用鸢尾花数据集: X 为特征向量,y 为标签向量
iris = datasets.load_iris()
X = iris['data']
y = iris['target']

# 定义候选值,对于二分类模型,通常选取20以内的奇数
k_candidate = [i for i in range(1,20) if i%2!=0]
# 进行10折交叉验证,返回的是训练集和验证集的下标
# KFold,StratifiedKFold中选择StratifiedKFold是考虑数据分布,选择KFold为考虑均分
# fk = KFold(n_splits=N, shuffle=True, random_state=521)
fk = StratifiedKFold(n_splits=N, shuffle=True, random_state=521)


# 预设准确率
maximum_accuracy = 0
# 预设best的k
best_k = choice(k_candidate)


# 遍历所有的候选值
for k in k_candidate:
    # 记录10段的准确率之和 
    count_accuracy = 0
    # 遍历10段的数据集
    # for train_index,valid_index in fk.split(X):
    for train_index,valid_index in fk.split(X,y):
        # 实例化KNN模型
        clf = KNeighborsClassifier(n_neighbors=k)
        # 训练模型
        clf.fit(X[train_index], y[train_index])
        # 统计累计准确率
        count_accuracy = count_accuracy + clf.score(X[valid_index], y[valid_index])
    # 计算KNN模型的K值为k时的平均准确率值
    count_accuracy = count_accuracy/N
    print('平均准确率为:%.2f' % count_accuracy)
    # 判断平均准确率值是否大于目前最大的准确率值
    if count_accuracy > maximum_accuracy:
        # 将平均准确率值替代原先最大的准确率值
        maximum_accuracy = count_accuracy
        # 将目前的K值替换原先最好的K值
        best_k = k
    print('当前最好的K值为:%d'%best_k,"当前最大的准确率值为:%.2f"%maximum_accuracy)
    print("*"*60)
print('评估最合适的K值为:%d'%best_k,"其准确率为:%.2f"%maximum_accuracy)
'''

2.4 K邻近算法回归模型简单示范版


#--------------------------------4.k临近算法回归模型---------------------------------#
# k临近算法回归模型
from sklearn.neighbors import KNeighborsRegressor
X = [[1,2],[3,4],[5,6],[7,8],[9,10]]
y = [1,2,3,4,5]
model = KNeighborsRegressor(n_neighbors=2)
model.fit(X,y)
model.predict([[5,5]])
# 输出:array([2.5])

常见问题

1、不平衡的样本可以给KNN的预测结果造成哪些问题,有没有什么好的解决方式?

输入实例的K邻近点中,大数量类别的点会比较多,但其实可能都离实例较远,这样会影响最后的分类。
可以使用权值来改进,距实例较近的点赋予较高的权值,较远的赋予较低的权值。

2、为了解决KNN算法计算量过大的问题,可以使用分组的方式进行计算,简述一下该方式的原理。

先将样本按距离分解成组,获得质心,然后计算未知样本到各质心的距离,选出距离最近的一组或几组,再在这些组内引用KNN。本质上就是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本,该方法比较适用于样本容量比较大时的情况。

3、KNN与K-means的区别

KNN

  • 分类算法
  • 监督学习
  • 数据集是带Label的数据
  • 没有明显的训练过程,基于Memory-based learning
  • K值含义 - 对于一个样本X,要给它分类,首先从数据集中,在X附近找离它最近的K个数据点,将它划分为归属于类别最多的一类

K-means

  • List item
  • 聚类算法
  • 非监督学习
  • 数据集是无Label,杂乱无章的数据
  • 有明显的训练过程
  • K值含义- K是事先设定的数字,将数据集分为K个簇,需要依靠人的先验知识

>Kmeans算法的缺陷:

聚类中心的个数K 需要事先给定,但在实际中这个 K 值的选定是非常难以估计的,很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适
Kmeans需要人为地确定初始聚类中心,不同的初始聚类中心可能导致完全不同的聚类结果。(可以使用Kmeans++算法来解决)

Q:参数调优后准确率变低了是因为只对个别参数调优导致不全的结果吗?

参考文章:
原文链接:https://blog.csdn.net/pengjunlee/article/details/82713047

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值