机器学习-KNN算法

1.机器学习之算法基本分类

本篇学习KNN算法,属于有监督学习,其余分类可做了解

1.1有监督学习(Supervised learning)

数据集中的每个样本有相应的“正确答案”, 根据这些样本做出
预测, 分有两类: 回归问题和分类问题。

步骤1: 数据集的创建和分类
步骤2: 训练
步骤3: 验证
步骤4: 使用

( 1) 回归问题举例
例如: 预测房价, 根据样本集拟合出一条连续曲线。
( 2) 分类问题举例
例如: 根据肿瘤特征判断良性还是恶性,得到的是结果是“良性”或者“恶性”, 是离散的。

监督学习:从给定的训练数据集中学习出一个函数(模型参数), 当新的数据到来时,可以根据这个函数预测结果。监督学习的训练集要求包括输入输出,也可以说是特征和目标。训练集中的目标是由人标注的。
PCA和很多deep learning算法都属于无监督学习

1.2无监督学习

无监督学习:输入数据没有被标记,也没有确定的结果。样本数据类别未知, 需要根据样本间的相似性对样本集进行分类(聚类, clustering)试图使类内差距最小化,类间差距最大化。
实际应用中, 不少情况下无法预先知道样本的标签,也就是说没有训练样本对应的类别,因而只能从原先没有样本标签的样本集开始学习分器设计

有监督学习无监督学习
样本必须要有训练集与测试样本。在训练集中找规律,而对测试样本使用这种规律。必须要有训练集与测试样本。在训练集中找规律,而对测试样本使用这种规律。
目标方法是识别事物,识别的结果表现在给待识别数据加上了标签。 因此训练样本集必须由带标签的样本组成。方法是识别事物,识别的结果表现在给待识别数据加上了标签。 因此训练样本集必须由带标签的样本组成。

1.3 半监督学习

半监督学习: 即训练集同时包含有标记样本数据和未标记样本数据。

1.4强化学习

实质是: make decisions问题,即自动进行决策,并且可以做连续决策。
主要包含四个元素: agent, 环境状态, 行动, 奖励;
强化学习的目标就是获得最多的累计奖励。

2.KNN算法

2.1KNN算法简介

K最近邻 (k-Nearest Neighbors, KNN) 算法是一种分类算法, 1968年由 Cover和 Hart 提出, 应用场景有字符识别、 文本分类、 图像识别等领域。

所谓 K 最近邻,就是 K 个最近的邻居的意思,说的是每个样本都可以用它最接近的 K 个邻近值来代表。K值由我们自己规定,具体数值需要视情况而定,我们下面会说到如何确定K值

2.2算法原理思想

该算法的思想是: 一个样本与数据集中的k个样本最相似, 如果这k个样本中的大多数属于某一个类别, 则该样本也属于这个类别。

KNN分类算法的分类预测过程十分简单并容易理解:对于一个需要预测的输入向量x,我们只需要在训练数据集中寻找k个与向量x最近的向量的集合,然后把x的类别预测为这k个样本中类别数最多的那一类。
在这里插入图片描述
如图所示,ω1、ω2、ω3分别代表训练集中的三个类别。其中,与xu最相近的5个点(令K值为5)如图中箭头所指,很明显与其最相近的5个点中最多的类别为ω1,因此,KNN算法将xu的类别预测为ω1。

如果明白了KNN算法基本原理后,请思考一个问题,上面我提到了K值选定有自己的规则,如果K值不同我们的预测结果会受到很大影响。
在这里插入图片描述
如上图所示,图中的数据可以分为蓝色正方形和红色三角形两类,图中心的绿色圆点是待分类数据,下面我们通过 K 最近领法对绿色圆点进行分类:

  1. k = 3 k=3 k=3 时,由图中实线圆内的数据可知:绿色圆点最近领的三个邻居中,一共有一个蓝色正方形和两个红色三角形,那么就可以将绿色圆点和红色三角形判定为一类。
  2. k = 5 k=5 k=5 时,由图中虚线圆内的数据可知:绿色圆点最近领的五个邻居中,一共有三个蓝色正方形和两个红色三角形,那么就可以将绿色圆点和蓝色正方形判定为一类。

至此,我们对 KNN 算法已经有了大概的了解。

2.3算法步骤

2.3.1初始化训练集

初始化训练集和测试集。训练集一般为两类或者多种类别的数据;测试集一般为一个数据。

2.3.2 距离计算&寻找K个最邻近数据

我们学习KNN原理可以已经明白要想预测分类需要寻找K个最邻近数据来做测试数据的分类预测依据。但是如何寻找K个最邻近数据?
最邻近顾名思义是距离最近,这里的距离和长度不同,它指的是不同数据间的相似程度。而这种距离我们需要通过距离公式计算。

距离计算

计算测试数据到其他所有数据的距离,并记录下来。常用到的距离计算公式如下:
①欧几里得距离(欧氏距离): d = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 d=\sqrt{(x_{1}-x_{2})^{2}+(y_{1}-y_{2})^{2}} d=(x1x2)2+(y1y2)2
②曼哈顿距离
③闵可夫斯基距离
④切比雪夫距离
⑤马氏距离
⑥余弦相似度
⑦皮尔逊相关系数
⑧汉明距离
⑨杰卡德相似系数
⑩编辑距离
⑪DTW 距离
⑫KL 散度

样本空间内的两个点之间的距离量度表示两个样本点之间的相似程度:距离越短,表示相似程度越高;反之,相似程度越低。

计算完测试数据与所有训练数据的距离后,我们就可以找到K个最邻近数据。

K值的选择

  • K 值的选择会对算法的结果产生重大影响。
  • K 值较小意味着只有与测试数据较近的训练实例才会对预测结果起作用,容易发生过拟合。
  • 如果 K 值较大,优点是可以减少学习的估计误差,但缺点是学习的近似误差增大,这时与测试数据较远的训练实例也会对预测起作用,使预测发生错误。
  • 在实际应用中,K 值一般选择一个较小的数值,通常采用交叉验证的方法来选择最优的 K 值。随着训练实例数目趋向于无穷和 K=1 时,误差率不会超过贝叶斯误差率的 2 倍,如果 K 也趋向于无穷,则误差率趋向于贝叶斯误差率。(贝叶斯误差可以理解为最小误差)

近似误差:可以理解为对现有训练集的训练误差。
估计误差:可以理解为对测试集的测试误差。

三种交叉验证方法:

  • Hold-Out: 随机从最初的样本中选出部分,形成交叉验证数据,而剩余的就当做训练数据。 一般来说,少于原本样本三分之一的数据被选做验证数据。常识来说,Holdout 验证并非一种交叉验证,因为数据并没有交叉使用。
  • K-foldcross-validation:K 折交叉验证,初始采样分割成 K 个子样本,一个单独的子样本被保留作为验证模型的数据,其他 K-1 个样本用来训练。交叉验证重复 K 次,每个子样本验证一次,平均 K 次的结果或者使用其它结合方式,最终得到一个单一估测。这个方法的优势在于,同时重复运用随机产生的子样本进行训练和验证,每次的结果验证一次,10 折交叉验证是最常用的。
  • Leave-One-Out Cross Validation:正如名称所建议, 留一验证 (LOOCV) 意指只使用原本样本中的一项来当做验证资料, 而剩余的则留下来当做训练资料。 这个步骤一直持续到每个样本都被当做一次验证资料。 事实上,这等同于 K-fold 交叉验证是一样的,其中 K 为原本样本个数。

2.3.3.决策分类

K值确定后,我们就可以明确 K 个邻居中所有数据类别的个数,将测试数据划分给个数最多的那一类。即由输入实例的 K 个最临近的训练实例中的多数类决定输入实例的类别。

最常用的两种决策规则

  • 多数表决法:多数表决法和我们日常生活中的投票表决是一样的,少数服从多数,是最常用的一种方法。

多数表决法很好理解,就是K个最邻近数据都有标签,即已经分好类。K个数据那类标签所占比最大则将测试数据分类为该类。

  • 加权表决法:有些情况下会使用到加权表决法,比如投票的时候裁判投票的权重更大,而一般人的权重较小。所以在数据之间有权重的情况下,一般采用加权表决法。
    在这里插入图片描述

2.4 过程总结

流程:
1) 计算已知类别数据集中的点与当前点之间的距离
2) 按距离递增次序排序
3) 选取与当前点距离最小的k个点
4) 统计前k个点所在的类别出现的频率
5) 返回前k个点出现频率最高的类别作为当前点的预测分类

2.5 KNN算法优缺点

优点

  • 所选择的邻居都是已经正确分类的对象
  • KNN 算法本身比较简单,分类器不需要使用训练集进行训练,训练时间复杂度为 0。本算法分类的复杂度与训练集中数据的个数成正比。
  • 对于类域的交叉或重叠较多的待分类样本,KNN 算法比其他方法跟合适。

缺点

  • 当样本分布不平衡时,很难做到正确分类
  • 计算量较大,因为每次都要计算测试数据到全部数据的距离。

3.实例&代码(python)

import matplotlib.pyplot as plt
import matplotlib
from math import sqrt

##### 初始化数据集 #####
data_A = [[1,2],[3.2,4],[6,7],[5.2,3],[7,4.1]]#数据集 A
data_B = [[2.2,5.5],[4.2,3],[5,8.1],[6.3,7],[2.5,6]]#数据集 B
test_data = [[4.5,4.5]]#测试集
len_A = len(data_A)
len_B = len(data_B)

##### 计算距离并排序 #####
distance_A = []#与 A 类数据之间的距离
distance_B = []#与 B 类数据之间的距离
distance = []#全部距离
#计算距离(使用欧氏距离)
for i in range(len_A):
    d = sqrt((test_data[0][0]-data_A[i][0])**2+(test_data[0][1]-data_A[i][1])**2)
    distance_A.append(d)
for i in range(len_B):
    d = sqrt((test_data[0][0]-data_B[i][0])**2+(test_data[0][1]-data_B[i][1])**2)
    distance_B.append(d)
#由小到大排序(此处使用冒泡排序)
distance = distance_A + distance_B
for i in range(len(distance)-1):
    for j in range(len(distance)-i-1):
        if distance[j] > distance[j+1]:
            distance[j],distance[j+1]=distance[j+1],distance[j]
print("距离所有A类数据的距离为:")
print(distance_A)
print("距离所有B类数据的距离为:")
print(distance_B)
print()
print("对所有的距离升序排序:")
print(distance)
print()

##### 按 K 最近领对测试集进行分类 #####
K = 5#这里默认 K 值为 5,也可以自行更改
number_A = 0
number_B = 0
#定义删除函数,避免对同一个数据重复计算
def delete(a,b,ls):
    for i in range(b):
        if ls[i]==a:
            ls.pop(i)
            break
#找出与测试数据最接近的 K 个点
for i in range(K):
    if distance[i] in distance_A:
        number_A += 1
        delete(distance[i],len(distance_A),distance_A)
        continue
    if distance[i] in distance_B:
        number_B += 1
        delete(distance[i],len(distance_B),distance_B)
        continue
print("最终结果:")
print("距离待测数据最近的K={:}个数据中,A类数据有{:}个,B类数据有{:}个".format(K,number_A,number_B))
if number_A > number_B:
    print("所以K={:}时,待测数据划分为A类".format(K))
else:
    print("所以K={:}时,待测数据划分为B类".format(K))

##### 画图 #####
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
for i in range(len_A):#A 类,用红色三角形表示
    if i!=len_A-1:
        plt.plot(data_A[i][0],data_A[i][1],'bo',marker='^',color='red')
    else:
        plt.plot(data_A[i][0],data_A[i][1],'bo',marker='^',label='A',color='r')
    #使用 if..else... 是为了避免在图形中重复出现多个标签
for i in range(len_B):#B 类,用蓝色正方形表示
    if i!=len_B-1:
        plt.plot(data_B[i][0],data_B[i][1],'bo',marker='s',color='blue')
    else:
        plt.plot(data_B[i][0],data_B[i][1],'bo',marker='s',label='B',color='b')
plt.plot(test_data[0][0],test_data[0][1],'bo',label='待测数据',color='g')#测试集
plt.xlim(0,10)
plt.ylim(0,10)
plt.legend()
plt.show()

输出结果:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

import math

movie_data = {"宝贝当家": [45, 2, 9, "喜剧片"],
              "美人鱼": [21, 17, 5, "喜剧片"],
              "澳门风云3": [54, 9, 11, "喜剧片"],
              "功夫熊猫3": [39, 0, 31, "喜剧片"],
              "谍影重重": [5, 2, 57, "动作片"],
              "叶问3": [3, 2, 65, "动作片"],
              "伦敦陷落": [2, 3, 55, "动作片"],
              "我的特工爷爷": [6, 4, 21, "动作片"],
              "奔爱": [7, 46, 4, "爱情片"],
              "夜孔雀": [9, 39, 8, "爱情片"],
              "代理情人": [9, 38, 2, "爱情片"],
              "新步步惊心": [8, 34, 17, "爱情片"]}

# 测试样本  唐人街探案": [23, 3, 17, "?片"]
#下面为求与数据集中所有数据的距离代码:
x = [23, 3, 17]
KNN = []
for key, v in movie_data.items():
    d = math.sqrt((x[0] - v[0]) ** 2 + (x[1] - v[1]) ** 2 + (x[2] - v[2]) ** 2)
    KNN.append([key, round(d, 2)])

# 输出所用电影到 唐人街探案的距离
print(KNN)

#按照距离大小进行递增排序
KNN.sort(key=lambda dis: dis[1])

#选取距离最小的k个样本,这里取k=5;
KNN=KNN[:5]
print(KNN)

#确定前k个样本所在类别出现的频率,并输出出现频率最高的类别
labels = {"喜剧片":0,"动作片":0,"爱情片":0}
for s in KNN:
    label = movie_data[s[0]]
    labels[label[3]] += 1
labels =sorted(labels.items(),key=lambda l: l[1],reverse=True)
print(labels,labels[0][0],sep='\n')

输出为
在这里插入图片描述

实例与代码来自:https://blog.csdn.net/saltriver/article/details/52502253
本篇内容学习自:
http://jiang-hs.gitee.io/jiang/

https://blog.csdn.net/sinat_30353259/article/details/80901746

https://blog.csdn.net/hajk2017/article/details/82862788?spm=1001.2014.3001.5501

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值