数据分析与数据挖掘 - 09邻近算法

一 邻近算法的基本介绍

1 基本说明

邻近算法又叫作K临近算法或者KNN(K-NearestNeighbor),是机器学习中很是重要的一个算法,but它简单得一塌糊涂,其核心思想就是样本的类别由距离其最近的K个邻居投票来决定。如今假设咱们已经有一个已经标记好的数据集,也就是说咱们已经知道了数据集中每一个样本所属于的类别。这个时候咱们拥有一个未标记的数据样本,咱们的任务是预测出来这个数据样本所属于的类别。显然邻近算法是属于监督学习(Supervised Learning)的一种,它的原理是计算这个待标记的数据样本和数据集中每一个样本的距离,取其距离最近的k个样本,那么待标记的数据样本所属于的类别,就由这距离最近的k个样本投票产生。在这个过程当中,有一个动做是标记数据集,这一点在企业中通常是有专门人来负责标记数据的。python

2 举例说明

为了更加直观的了解邻近算法,请看下面的例子。有两种水果长得很是像,一个是菠萝,另外一个是凤梨,很长一段时间我都觉得它们是同一种水果。
WechatIMG78.png
菠萝与凤梨的核心区别是菠萝的叶子有刺,而凤梨的叶子没有刺。菠萝的凹槽处的颜色是黄色,而凤梨的凹槽处的颜色是绿色。首先咱们把这两种水果抽取出其中的两个特色(凹槽处的颜色、叶子上是否有刺)后,放入一个直角坐标系中吧。以下图:
WechatIMG79.png
咱们按照两种水果的特色,已经把它们放在了直角坐标系中,按照咱们所说的算法原理,此时有一个未标记的样本,咱们来预测这个样本究竟是属于哪一种水果。以下图,这个时候来了一个未标记的样本,也就是不知道是什么类别的水果。
WechatIMG80.png
在原理中,咱们说过,由其最近的K个邻居来投票决定,这个未标记的水果究竟是什么水果,那么这个时候,咱们把K的值设置为3,以下图:
WechatIMG81.png
从图片中,咱们看到,在K的值为3的时候,与未标记样本最近的3个邻居其中2个为菠萝,而1个为凤梨,那么这个时候咱们预测这个未知的水果为菠萝。算法

3 伪代码说明

咱们先来看一下如何用伪代码来实现这个算法,这样咱们在后边的学习中才能更好的写出来这段代码。数组

  • 第一步,咱们设x_test为待标记的数据样本,x_train为已标记的数据集。
  • 第二步,遍历x_train中的全部样本,计算每一个样本与x_test的距离,并把距离保存在distance数组中。
  • 第三步,对distance数组进行排序,取距离最近的k个点,标记为x_knn。
  • 第四步,在x_knn中统计每一个类别的个数,即class0(类别0)在x_knn中有几个样本,class1 (类别1)在x_knn中有几个样本。
  • 第五步,待标记样本的类别,就是x_knn中样本个数最多的那个类别。

4 优缺点分析

  • 优势:准确性高,对异常值有较高的容忍度,缘由是异常值会单独分布在坐标系的一个角落,取k个邻居的时候大几率失去不到这个异常值的。
  • 缺点:计算量大,对内存的需求也大,由于它每次对一个未标记的样本进行分类的时候,都须要所有计算一下距离。
  • 关键点:k值的选取,首先k值必定是奇数,这样能够确保两个类别的投票不会同样,其次,k值越大,模型的误差越大,对于噪声数据(错误数据或异常数据)越不敏感,k值过小就会形成模型的过拟合。

二 邻近算法的代码练习

1 准备数据

# 从sklearn库中的数据集对象里导入样本生成器中的make_blobs方法帮助咱们生成数据
from sklearn.datasets.samples_generator import make_blobs

# 声明三个直角坐标系中的位置
centers = [[-2, 2], [2, 2], [0, 4]]

# 生成数据,其中n_samples是生成数据的个数,centers是中心点,cluster_std是标准差,指明离散程度
x, y = make_blobs(n_samples=60, centers=centers, cluster_std=0.6)

# x是生成的数据,y是不一样的数据对应所属的的类别0,1,2
print(x, y)

2 用图形来帮助理解

import matplotlib.pyplot as plt
import numpy as np

plt.figure(figsize=(16, 10), dpi=144)
c = np.array(centers)
# x轴,y轴,c颜色  s指定点的大小
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()

图形显示以下图所示:
image.png
图形中显示的三个三角形的点就是中心点,围绕在它们周围的圆点就是咱们随机生成的数据的点。app

3 KNN算法对数据的训练

# 从sklearn库中导入K邻居分类器:KNeighbosrClassifier
from sklearn.neighbors import KNeighborsClassifier

# 设定K值
k = 5

# 声明k临近分类器对象
clf = KNeighborsClassifier(n_neighbors=k)

# 训练模型
clf.fit(x, y)

4 预测样本数据

# 定义样本数据
x_sample = [[0, 2]]
# 使用模型进预测
neighbors = clf.kneighbors(x_sample, return_distance=False)
print(neighbors)

# 输出值:[[23 39 21 47 29]]

x_sample变量是咱们要进行预测的样本,而后使用clf.kneighbors方法就能够对这个样本进行预测了。关于clf.kneighbors的参数return_distance,它决定了是否返回计算后的距离,默认是True,这里我把它修改为了False,你若是想要看一下值为True是什么样子,能够本身手动修改成True。到这里你能够有一点懵,这怎么就预测完成了呢?输出值表示的是什么意思呢?


输出值表示的是5个通过计算以后的位于x训练集中的索引值,它们并非直接的位置。机器学习

5 画出预测的结果

为了可以使预测的结果更加直观,咱们还须要用代码把他们画出来。学习

# 把带预测的样本以及和其最近的5个点标记出来
plt.figure(figsize=(8, 5), dpi=144)  # dpi是像素值
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()

显示结果以下图所示:
image.png测试

三 花卉识别项目练习

1 先认识三朵花

在这一小节咱们将经过一个花卉识别项目的练习来巩固咱们所讲的KNN算法,训练数据集是很是著名的鸢尾花数据集,涉及到的花的种类一共分为三种:


第一种花是山鸢尾,长下面这个样子
image.png
第二种花是锦葵,也叫虹膜锦葵
image.png
第三种花是变色鸢尾
image.pngui

2 导入数据集

咱们能够经过sklearn库的自带数据集直接引入鸢尾花的数据集,在这个数据集中,咱们能够经过花萼长度,花萼宽度,花瓣长度和花瓣宽度四个属性来预测未标记的鸢尾花属于哪一个类别。rest

# 1 导入鸢尾花数据集
from sklearn.datasets import load_iris

# 2 声明一个鸢尾花的类对象
iris = load_iris()

# 3 获取鸢尾花的数据
iris_data = iris.data

# 4 获取数据对应的种类
iris_target = iris.target

print(iris_data)
print(iris_target)

查看数据后你会看到iris_data变量里每个元素一共有4个值,这四个值就是分别对应花萼长度、花萼宽度、花瓣长度、花瓣宽度4个属性,iris_target变量对应的就是每个花所属的类别。一共对应的是3个类别,0的意思是山鸢尾,1是虹膜锦葵,2是变色鸢尾。code

3 训练模型

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split  # 分割训练集和测试集
from sklearn.neighbors import KNeighborsClassifier

iris = load_iris()
iris_data = iris.data
iris_target = iris.target

# 把数据分为训练集和测试集,x表示特征值,y表示目标值,test_size=0.25表示将25%的数据用做测试集
x_train, x_test, y_train, y_test = train_test_split(iris_data, iris_target, test_size=0.25)

# 建立KNN算法实例,n_neighbors参数默认为5,后续能够经过网格搜索获取最优参数
knn = KNeighborsClassifier(n_neighbors=5)

# 训练测试集数据
knn.fit(x_train, y_train)

# 获取预测结果
y_predict = knn.predict(x_test)

# 展现预测结果
labels = ['山鸢尾', '虹膜锦葵', '变色鸢尾']
for i in range(len(y_predict)):
    print('第%d次测试:预测值:%s 真实值:%s' %((i + 1), labels[y_predict[i]], labels[y_test[i]]))
print('准确率:', knn.score(x_test, y_test))

4 获取k值最优参数

k值选取的思路是咱们先来选择一个k值的范围,把这个范围中全部的偏差值都获取到,而后咱们再来选择偏差最小的值做为k值。

from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt

# 中文显示
plt.rcParams["font.family"] = 'Arial Unicode MS'

# 导入数据集
iris = load_iris()
x = iris.data
y = iris.target

# 限制k的取值范围
k_range = range(1, 31)

# 记录每当k值变换一次,它的错误值是多少
k_error = []


for k in k_range:
    knn = KNeighborsClassifier(n_neighbors=k)
    
    # cv参数决定数据集划分比例,这里按照5:1划分训练集和测试集
    scores = cross_val_score(knn, x, y, cv=6)
    print(scores)
    
    k_error.append(1 / scores.mean())

# 把结果画成图,直观看出k取什么值偏差最小,x轴为k值,y轴为偏差值
plt.plot(k_range, k_error)
plt.xlabel('k值')
plt.ylabel('偏差值')
plt.show()

图形显示结果以下图所示:
image.png
根据这个图形咱们就能够看得出来,k值大概是在12这个位置时,偏差是最小的。这时当咱们把12从新放入到以前的代码中,可能你会发现他的准确率并无提高甚至还有可能降低了,实际上是由于数据量比较小的缘故,并不影响咱们解决问题的方式。

四 KNeighborsClassifier参数详解

经过前面的练习,相信你已经基本掌握了KNeighborsClassifier的使用方法了,最后,在这里咱们会对这个方法的参数进行更细致的说明和讲解。

# 查看KNeighborsClassifier源代码
NeighborsClassifier(
    n_neighbors=5,
    weights="uniform”,
    algorithm=”auto“,
    leaf_size=30,
    p=2,
    metric="minkowski",
    metric_params=None,
    n_jobs=None,
    **kwargs,
)
  • weights用于指定临近样本的投票权重,默认是uniform,表示全部邻近样本投票权重都是同样的。若是咱们把weights的值设置成distance,表示投票权重与距离成反比,也就是说邻近样本与未知类别样本距离越远,则其权重越小,反之,权重越大。
  • algorithm用于指定邻近样本的搜寻方法,若是值为ball_tree,表示用球树搜寻法寻找近邻样本,kd_tree就是KD树搜寻法,brute是使用暴力搜寻法。algorithm默认参数是auto,表示KNN算法会根据数据特征自动选择最佳搜寻方法。关于这些搜寻法的细节,我会在将来发布的机器学习的文章中作详细的说明,如今只须要知道咱们当前用的是默认的自动帮咱们选择的搜寻方法。
  • leaf_size用于指定球树或者KD树叶子节点所包含的最小样本量,它用于控制树的生长条件,会影响查询速度,默认值是30,目前咱们先不关注这个点。
  • metric参数是用来指定距离的度量指标,默认为闵可夫斯基距离。
  • p参数是依赖metric参数生效的,当metric为minkowski距离时,p=1表示计算点之间的曼哈顿距离,p=2表示计算点之间的欧式距离,默认值为2,计算欧式距离。
  • metric_params是一个字典,默认值为空,它为metric参数所对应的距离指标添加关键字参数。
  • n_jobs设置KNN算法并行计算时所需的CPU数量,默认值为1,表示仅使用一个CPU运行算法,也就是不开启并行运算。


一样的,最后咱们会有一个小的练习,请点击下方连接下载:
chapter9-1.zip

相关文章
相关标签/搜索