k近邻法原理及编程实现

算法描述

给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的k个实例,这k个实例的多数属于某个类,就把该输入实例分为这个类。

三个基本要素

1.距离度量
两个实例之间的距离可以用 L p L_p Lp范数来定义,其中p可以选择。 L P L_P LP范数的定义为:
在这里插入图片描述
这里面的 x i x_i xi x j x_j xj代表两个实例,这两个实例都有n个分量。
比较常用的是p=2,此时称为欧氏距离,即:
在这里插入图片描述
例如 x i = ( 1 , 2 , 3 ) x_i=(1,2,3) xi=(1,2,3) x j = ( 4 , 5 , 6 ) x_j=(4,5,6) xj=(4,5,6),则这两个实例之间的欧氏距离为:
d i s t a n c e = ( ∣ 1 − 4 ∣ 2 + ∣ 2 − 5 ∣ 2 + ∣ 3 − 6 ∣ 2 ) 1 / 2 distance=(|1-4|^2+|2-5|^2+|3-6|^2)^{1/2} distance=(142+252+362)1/2

2.k值选择
k选的小的话近似误差会减小,但估计误差会增大。

k选的大的话近似误差会增大,估计误差会减小。
比如k选1的话,对一个点进行分类的时候就只找到与它距离最近的1个点就行,所找到的点的类别就是这个点的类别。但在实际情况下会有噪声点,这时k=1就很容易分错了。如下图所示,○是一类,×是另一类,此时放入一个△,直观上觉得它属于○这一类的概率大一些,但是由于噪声的存在,如果k=1的话因为离△最近的是一个×,这时就会把△分到×类,如果k=3的话就会把△分到○类。
在这里插入图片描述
另一个例子如下:
在这里插入图片描述
在这个例子中如果k=1或k=2的话是可以正确地把△分在○类里面的,如果k取一个特别大的值的话△就会被错误地分到×中去。

3.分类决策规则
一般都是用多数表决,即离输入实例最近的k个实例属于哪个类别的实例数量最多那么输入实例就属于哪个类别。

代码

import numpy as np
import operator


class Knn:
    def __init__(self, point, samples, labels, k):
        self.point = point
        self.samples = samples
        self.labels = labels
        self.k = k

    def distance(self, lp):
        """计算要进行分类的点与样本之间的距离(lp范数)"""
        samples_len = len(self.samples)
        subtract = np.tile(self.point, (samples_len, 1)) - self.samples
        absolute_value = abs(subtract)
        p_power = absolute_value ** lp
        sum_value = p_power.sum(axis=1)
        p_norm = sum_value ** (1/lp)
        return p_norm

    def classification(self, distances):
        small_to_large_index = distances.argsort()  # argsort函数返回的是数组值从小到大的索引值
        class_count = {}
        for i in range(self.k):
            near_label = self.labels[small_to_large_index[i]]

            # 统计前k个中标签的数目
            # 也就是说最后这个字典中存的是A类的有多少个,B类的有多少个
            # 字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值
            class_count[near_label] = class_count.get(near_label, 0) + 1

        # reverse=True代表逆序排列
        # key=operator.itemgetter(1)定义函数key为获取对象的序号为1的值,也就是比较value,如果括号里为0就是比较key
        # sorted是个排序函数
        # class_count.items()为字典里面的内容
        sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
        return sorted_class_count[0][0]


samples_out = [[1, 2], [3, 4], [5, 6], [7, 8]]
labels_out = ['A', 'A', 'B', 'B']
knn = Knn([0, 0], samples_out, labels_out, 3)
distance_out = knn.distance(2)
classification_result = knn.classification(distance_out)
print(classification_result)

结果为:

A
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

comli_cn

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

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

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

打赏作者

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

抵扣说明:

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

余额充值