机器学习 之 KNN邻近算法

KNN的自述

Km模型仍为有监督的学习算法。它属于一种惰性学习算法,即不会预先生成一个分类或预测模型,用于新样本的预测,而是将模型的构建与未知数据的预测同时进行,该算法与决策术功能类似既可以针对离散性变量作出分类,又可以对于连续型变量作出预测,其核心思想就是比较已知y值的样本与未知y值样本的相似度,然后寻找最相似的K个样本用作未知样本的预测,该算法在实际应用中还是比较广泛的,并且不需要高深的数据基础

原理

最 K最邻近算法顾名思义就是搜索最近的K个已知样本用于未知样本的预测,最近就是应用点之间的距离或相似性,距离越小,则相似度越高,说明它们之间越近,关于样本间的远近的度量,有几种方法。对于离散型样本来说,从K个最近的已知类别样本中,挑选出频率最高的类别用于未知样本的判断,对于连续型变量来说,则将K个最近的已知样本均值用作样本的预测。
在这里插入图片描述
假设数据集中一共含有两类样本,分别用五角星和三角形来表示,带预测样本为圆的圆心,如果以邻近个数K为5为例,就可以通过投票的方式快速得到未知样本所属的类别,具体有三个步骤:

  • 确定未知样本临近的个数K
  • 根据某种度量样本间的相似度,将每一个未知类别样本的最近K个已知样本搜索出来,形成一个个簇
  • 对于搜索出来的已知样本进行投票,将各簇下类别最多的分类用于未知样本点的预测

KNN分类的思想是计算未知分类的样本点与已知分类的样本点之间的距离,然后将未知分类最近的K个已知分类用作投票,所以该算法的一个重要步骤就是计算他们之间的相似性。
计算方法有四种:

  1. 欧式距离:
    在这里插入图片描述

  2. 曼哈顿距离:
    就是计算在N维上的投影的距离之和
    例如在平面上,坐标(x1,y1)的i点与坐标(x2,y2)的j点的曼哈顿距离为d(i,j)=|X1-X2|+|Y1-Y2|.

  3. 余弦相似度:
    在这里插入图片描述
    就是观测角度的差距

  4. 杰卡德距离可自行百度

关于临近样本的搜索方法有KD树搜索法和球数搜索法。

参数

from sklearn.neighbors import KNeighborsClassifier as KNN
KNN(n_neighbors=5 # 用于指定近邻样本个数K默认5
        ,weights="uniform" # 用于指定邻近样本的投票权重,“uniform”表示所有样本投票权重一致,如果为“distance”则表示投票权重与距离成反比
        ,algorithm="auto" # 用于指定近邻样本的搜索方法,auto表示会根据数据特征自动选择最佳搜索
        ,leaf_size=30 # 用于搜索方法时,节点所包含的最小样本量,用于控制数的生长,默认为30,一般不修改。
        ,metric="minkowski" # 用于指定距离的度量指标,默认闵可夫斯基距离一般不改
        ,p=2 #  P=1表示用曼哈顿距离,p=2表示欧式距离
        ,n_jobs=-1)

K值确定

一般来说K对于模型的预测准确性会有比较大的影响,如果K值偏小,可能会导致模型的过拟和,反之有可能会使模型进入欠拟合的状态。
为了获取最佳的K值,可以考虑两种解决方案,一种是设置K临近样本的权重。假设使用时K值比较大,担心模型发生欠拟合的现象,一个简单的方法就是设置临近样本的投票权重,如果已知样本距离未知样本距离比较远,主要对应的权重就设置比较低,否则权重就视为高一些,通常可以将权重设置为距离的倒数。另外是采用多重交叉验证的方法,也是目前比较流行的方法,其核心是将K取不同的值,然后在每种值下面执行交叉验证,最后选出平均误差最小的K值。

K和weights对模型的影响

from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.neighbors import KNeighborsClassifier as KNN

digits=load_digits()
x=pd.DataFrame(digits.data)
x_train,x_test,y_train,y_test=train_test_split(x,digits.target,test_size=0.3,random_state=10)

weights=["uniform","distance"]
colors=["red","green"]
fig=plt.figure(figsize=(8,5))
ax=fig.add_subplot(111)
for j,weight in enumerate(weights):
        scores_train = []
        scores_test=[]

        for i in range(1,10):
                knn=KNN(n_neighbors=i ,weights=weight).fit(x_train,y_train)

                score = cross_val_score(knn, x_train, y_train, cv=10).mean()
                scores_train.append(score)

                score=cross_val_score(knn,x_test,y_test,cv=10).mean()
                scores_test.append(score)
        ax.plot(range(1,10),scores_train,"--",color=colors[j], label =weight+" train")
        ax.plot(range(1,10), scores_test, "o-", color=colors[j], label =weight+" test")
        ax.legend()

ax.set_ylabel("cross_val_score")
ax.set_xlabel("K")
plt.show()

在这里插入图片描述
我们可以直观的看出来,经过distance参数取代uniform后,不管是训练集还是测试集,总体上的结果都比较好,并且从学习曲线上也可以直观的看出K=4为最佳选择。

KNN在不同数据集的表现

from sklearn.neighbors import KNeighborsClassifier as KNN
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_moons, make_circles, make_classification

######生成三种数据集######
# 二分类数据集
X, y = make_classification(n_samples=100, #生成100个样本
 n_features=2,#有两个特征
 n_redundant=0, #添加冗余特征0个
 n_informative=2, #包含信息的特征是2个
 random_state=1,#随机模式1
n_clusters_per_class=1 #每个簇内包含的标签类别有1个
 )
rng = np.random.RandomState(2) #生成一种随机模式
X += 2 * rng.uniform(size=X.shape) #加减0~1之间的随机数
linearly_separable = (X, y) #生成了新的X,依然可以画散点图来观察一下特征的分布
#plt.scatter(X[:,0],X[:,1])

#用make_moons创建月亮型数据,make_circles创建环形数据,并将三组数据打包起来放在列表datasets中
moons=make_moons(noise=0.3, random_state=0)
circles=make_circles(noise=0.2, factor=0.5, random_state=1)
datasets = [moons,circles,linearly_separable]


figure = plt.figure(figsize=(6, 9))
i=1
#设置用来安排图像显示位置的全局变量i i = 1
#开始迭代数据,对datasets中的数据进行for循环
for ds_index, ds in enumerate(datasets):
    X, y = ds
    # 对数据进行标准化处理
    X = StandardScaler().fit_transform(X)
    #划分数据集
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4,
random_state=42)

    #定数据范围,以便后续进行画图背景的确定
    #注意X[:,0]指横坐标,X[:,1]指纵坐标
    x1_min, x1_max = X[:, 0].min() - .5, X[:, 0].max() + .5
    x2_min, x2_max = X[:, 1].min() - .5, X[:, 1].max() + .5

    #使画板上每个点组成坐标的形式(没间隔0.2取一个),array1表示横坐标,array2表示纵坐标
    array1,array2 = np.meshgrid(np.arange(x1_min, x1_max, 0.2), np.arange(x2_min, x2_max, 0.2))
    # 颜色列表
    cm_bright = ListedColormap(['#FF0000', '#0000FF'])

########## 原始数据的现实  #########

    # 用画板上六个图片位置(3,2)的第i个
    ax = plt.subplot(len(datasets), 2, i)

    # 便签添加
    if ds_index == 0:
        ax.set_title("Input data")

    #画出训练数据集散点图
    ax.scatter(X_train[:, 0],#横坐标
               X_train[:, 1],#纵坐标
               c=y_train,#意思是根据y_train标签从cm_bright颜色列表中取出对应的颜色,也就是说相同的标签有相同的颜色。
               cmap = cm_bright, #颜色列表
               edgecolors = 'k'#生成散点图,每一个点边缘的颜色
               )
    #画出测试数据集的散点图,其中比训练集多出alpha = 0.4参数,以分辨训练测试集
    ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test,cmap = cm_bright, alpha = 0.4, edgecolors = 'k')
    #显示的坐标范围
    ax.set_xlim(array1.min(), array1.max())
    ax.set_ylim(array2.min(), array2.max())
    #不显示坐标值
    ax.set_xticks(())
    ax.set_yticks(())

    #i+1显示在下一个子图版上画图
    i += 1

####### 经过决策的数据显示 #######
    ax = plt.subplot(len(datasets), 2, i)
    #实例化训练模型
    gnd = KNN(n_neighbors=4,weights="distance").fit(X_train, y_train)
    score = gnd.score(X_test, y_test)

    # np.c_是能够将两个数组组合起来的函数
    # ravel()能够将一个多维数组转换成一维数组
    #通过对画板上每一个点的预测值确定分类结果范围,并以此为依据通,通过不同的颜色展现出来范围

    # 为了展示不同概率对应不同的颜色就不用这句代码作为contourf的z参数了Z = clf.predict(np.c_[array1.ravel(), array2.ravel()])
    # 通过计算每一个结果对应的概率,并选出其中的最大值作为contourf参数
    Z = gnd.predict_proba(np.c_[array1.ravel(), array2.ravel()])
    Z = Z[:,0].reshape(array1.shape)
    cm = plt.cm.RdBu # 自动选取颜色的实例化模型。
    ax.contourf(array1#画板横坐标。
                , array2#画板纵坐标
                , Z# 画板每个点对应的预测值m,并据此来确定底底板的颜色。
                , cmap=cm#颜颜色选取的模型,由于Z的值只有两个,也可以写出一个颜色列表,指定相应颜色,不让其自动生成
                , alpha=0.8
                )
    #和原始数据集一样,画出每个训练集和测试集的散点图
    ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright, edgecolors = 'k')
    ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, edgecolors = 'k', alpha = 0.4)
    ax.set_xlim(array1.min(), array1.max())
    ax.set_ylim(array2.min(), array2.max())
    ax.set_xticks(())
    ax.set_yticks(())

    if ds_index == 0:
        ax.set_title("KNN")

    #在右下角添加模型的分数
    ax.text(array1.max() - .3, array2.min() + .3, ('{:.1f}%'.format(score * 100)),
    size = 15, horizontalalignment = 'right')
    i += 1

#自动调整子画板与子画板之间的的距离
plt.tight_layout()
plt.show()

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「 25' h 」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值