跟我一起学scikit-learn15:K-近邻算法

KNN(K-Nearest Neighbor,K-近邻算法)算法是一种有监督的机器学习算法,可以解决分类问题,也可以解决回归问题。

1.KNN算法原理

K-近邻算法的核心思想是未标记样本的类别,由距离其最近的K个邻居投票来决定。

假设,我们有一个已经标记的数据集,即已经知道了数据集中每个样本所属的类别。此时,有一个未标记的数据样本,我们的任务是预测出这个数据样本所属的类别。K-近邻算法的原理是,计算待标记的数据样本和数据集中每个样本的距离,取距离最近的K个样本。待标记的数据样本所属的类别,就由这K个距离最近的样本投票产生。

假设X_test为待标记的数据样本,X_train为已标记的数据集,算法原理的伪代码如下:

  • 遍历X_train中的所有样本,计算每个样本与X_test的距离,并把距离保存在Distance数组中。
  • 对Distance数组进行排序,取距离最近的K个点,记为X_knn。
  • 在X_knn中统计每个类别的个数,即class0在X_knn中有几个样本,class1在X_knn中有几个样本等。
  • 待标记样本的类别,就是在X_knn中样本数最多的那个类别。
1.KNN算法的优缺点
  • 优点:准确度高,对异常值和噪声有较高的容忍度。
  • 缺点:计算量较大,对内存的需求也较大。从算法原理可以看出来,每次对一个未标记样本进行分类时,都需要全部计算一遍距离。
2.KNN算法的参数

其算法参数是K,参数选择需要根据数据来决定。K值越大,模型的偏差越大,对噪声数据越不敏感,当K值很大时,可能造成模型欠拟合;K值越小,模型的方差就会越大,当K值太小,就会造成模型过拟合。

3.KNN算法的变种

K-近邻算法有一些变种,其中之一就是可以增加邻居的权重。默认情况下,在计算距离时,都是使用相同的权重。实际上,我们可以针对不同的邻居指定不同的权重,如距离越近权重越高。这个可以通过指定算法的weights参数来实现。

另外一个变种是,使用一定半径内的点取代距离最近的K个点。在scikit-learn里,RadiusNeighborsClassifier类实现了这个算法的变种。当数据采样不均匀时,该算法变种可以取得更好的性能。

2.示例:使用KNN算法进行分类

在scikit-learn里,使用K-近邻算法进行分类处理的是sklearn.neightbors.KNeightborsClassifier类。
(1)生成已标记的数据集

from sklearn.datasets.samples_generator import make_blobs
# 生成数据
centers = [[-2,2],[2,2],[0,4]]
X,y = make_blobs(n_samples=60,centers=centers,random_state=0,cluster_std=0.60)

我们使用sklearn.datasets.samples_generator包下的make_blobs()函数来生成数据集,这里生成60个训练样本,这些样本分布在centers参数指定的中心点的周围。cluster_std是标准差,用来指明生成的点分布的松散程度。生成的训练数据集放在变量X里面,数据集的类别标记放在y里面。

我们可以把X和y的值打印出来查看,一个更直观的方法是使用matplotlib库,它可以很容易地把生成的点画出来:

import matplotlib.pyplot as plt
import numpy as np
plt.figure(figsize=(16,10),dpi=144)
c = np.array(centers)
plt.scatter(X[:,0],X[:,1],c=y,s=100,cmap='cool')
plt.scatter(c[:,0],c[:,1],s=100,marker='^',c='orange')
plt.show()

figure4_1.png
这些点的分布情况在坐标轴上一目了然,其中三角形的点即各个类别的中心点。
(2)使用KNeighborsClassifier来对算法进行训练,我们选择的参数是K=5

from sklearn.neighbors import KNeighborsClassifier
k = 5
clf = KNeighborsClassifier(n_neighbors=k)
clf.fit(X,y)

得到的模型如下:

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

(3)对一个新样本进行预测

X_sample = [0,2]
X_sample = np.array(X_sample).reshape(1, -1)
y_sample = clf.predict(X_sample)
neighbors = clf.kneighbors(X_sample,return_distance=False)

我们要预测的样本是[0,2],使用kneighbors()方法,把这个样本周围距离最近的5个点取出来。取出来的点是训练样本X里的索引,从0开始计算。
注意:kneighbors()接收一个二维数组作为参数,所以X_sample需要变成二维。
(4)把待预测的样本以及和其最近的5个点标记出来

plt.figure(figsize=(16,10),dpi=144)
plt.scatter(X[:, 0], X[:, 1], c=y, s=100, cmap='cool')    # 样本
plt.scatter(c[:, 0], c[:, 1], s=100, marker='^', c='k')   # 中心点
plt.scatter(X_sample[0][0],X_sample[0][1],marker="x", s=100, cmap='cool')  #待预测的点
#预测点与距离最近的5个样本的连线
for i in neighbors[0]:
    plt.plot([X[i][0],X_sample[0][0]],[X[i][1],X_sample[0][1]],'k--',linewidth=0.6)
plt.show()

figure4_2.png
从上图中可以清楚地看到KNN算法的原理。

3.示例:使用KNN算法进行回归拟合

分类问题的预测值是离散的,我们也可以使用KNN算法对连续区间内的数值进行预测,即进行回归拟合。在scikit-learn里面,使用KNN算法进行回归拟合的实现是sklearn.neighbors.KNeighborsRegressor类。
(1)生成数据集,在余弦曲线的基础上加入了噪声:

import numpy as np
n_dots = 40
X = 5 * np.random.rand(n_dots,1)
y = np.cos(X).ravel()
y += 0.2*np.random.rand(n_dots)-0.1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值