CSDN-markdown编辑器

KNN

  • 是什么/原理
  • 核心思想:“近朱者赤,近墨者黑”,由你的邻居来推断出你的类别
  • python实现
  • 算法不足之处

是什么/原理

  • k近邻法(KNN)是一种基本分类与回归方法,是“懒惰学习”的代表,其算法的时间复杂度是O(n),一般适用于样本数较少的数据集。其输出可以是多类。
  • k近邻法没有显式的学习过程,即没有训练阶段,数据集事先已有了分类和特征值,待收到新样本后直接进行处理。
  • 相似度衡量方法:包括欧式距离(p=2)、曼哈顿距离(p=1)、夹角余弦。
  • 简单应用中,一般使用欧氏距离,但对于文本分类来说,使用余弦来计算相似度就比欧式距离更合适。
  • K近邻法的三个基本要素是:k值的选择、距离度量、分类决策规则。

核心思想

k近邻法中k值的选择会对k近邻法的结果产生重大影响。选取的k值若较小,就相当于用较小的领域中的训练实例进行预测,“学习”的近似误差会减小,只有与输入实例较近的训练实例才会对预测结果起作用,但缺点是“学习”的估计误差会增大,预测结果会对近邻的实例点非常敏感。反之,若选取的k值较大,其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大。K值的增大意味整体的模型变得简单(k值越小模型越复杂,k值较小可能产生过拟合的现象)。所以在应用中,k值一般取一个比较小的数值,通常采用交叉验证法来选取最优的k值。

Q:什么是近似误差和估计误差?

近似误差可以理解为模型估计值与实际值之间的差距。
估计误差可以理解为模型的估计系数与实际系数之间的差距。
近似误差,更关注于“训练”。最小化近似误差,即为使估计值尽量接近真实值,这里的真实值指的是训练样本,模型本身并不是最接近真实分布。换一组样本可能就不近似了,这种训练样本表现好,测试样本表现不好的现象称为过拟合。
估计误差,更关注于“测试”、“泛化”。与近似误差相反,最小化估计误差,即为使估计系数尽量接近真实系数,可能此时对于训练样本得到的估计值不一定最接近真实值,但模型肯呢个更加接近真实分布。
avatar
如图(图片来自百度百科)
K值若较小,这里取内圈,红色三角占2/3,则绿色的未知物被判断为红色三角;
K值若较大,这里取外圈,蓝色方块占3/5,则绿色未知物被判断为蓝色方块。

实现

from numpy import *  # 引入科学计算包
import operator  # 经典python函数库。运算符模块。
# 创建数据集
def createDataSet():
    group = array([[1.0, 1.1], [1.0, 1.0], [0, 0], [0, 0.1]])
    labels = ['A', 'A', 'B', 'B']
    return group, labels

# 算法核心
# inX:用于分类的输入向量。即将对其进行分类。
# dataSet:训练样本集
# labels: 标签向量
def classfy0(inX, dataSet, labels, k):
# 距离计算(这里用的欧氏距离)
    dataSetSize = dataSet.shape[0]  # 得到数组的行数。即知道有几个训练数据
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet  # tile:numpy中的函数。tile将原来的一个数组,扩充成了4个一样的数组。diffMat得到了目标与训练数值之间的差值。
    sqDiffMat = diffMat ** 2  # 各个元素分别平方
    sqDistances = sqDiffMat.sum(axis=1)  # sum(axis=1)函数表示按行求和,一般默认

注释

axis=0即默认列求和
distances = sqDistances ** 0.5 # 开方,得到距离。
假如:(这里用的欧氏距离)
Newinput:[1,0,2]
Dataset:
[1,0,1]
[2,1,3]
[1,0,2]
计算过程即为:
1、求差
[1,0,1] – [1,0,2] = [0,0,-1]
[2,1,3] – [1,0,2] = [1,1,1]
[1,0,2] – [1,0,2] = [0,0,-1]

2、对差值平方
[0,0,1]
[1,1,1]
[0,0,1]
3、将平方后的差值累加
1
3
1
4、将上一步骤的值求开方,即得距离
1
1.73
1
这就是以上的步骤

代码块

sortedDistIndicies = distances.argsort()  # 升序排列
    # 选择距离最小的k个点。
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    # 排序
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)     #Python3.5中:iteritems变为items
    return sortedClassCount[0][0]

if __name__== '__main__':
    dataSet, labels = createDataSet()
    input = array([1.1, 0.3])
    K = 3
    output = classfy0(input, dataSet, labels, K)
print("测试数据为:", input, "分类结果为:", output)

算法不足之处

  1. 样本不平衡容易导致结果错误;
  2. 计算量较大。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值