KNN算法(学习笔记)

算法原理

K近邻(K-nearst neighbors, KNN)
所谓k近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。
KNN算法既可以应用于分类应用中,也可以应用在回归应用中。KNN在做回归和分类的主要区别在于最后做预测的时候的决策方式不同。 KNN在分类预测时,一般采用多数表决法;而在做回归预测时,一般采用平均值法

基本步骤:
1.从训练集合中获取K个离待预测样本距离最近的样本数据;
2.根据获取得到的K个样本数据来预测当前待预测样本的目标属性值。

KNN三要素

1.K值的选择:对于K值的选择,一般根据样本分布选择一个较小的值,然后通过交叉验证来选择一个比较合适的最终值;当选择比较小的K值的时候,表示使用较小领域中的样本进行预测,训练误差会减小,但是会导致模型变得复杂容易过拟合;当选择较大的K值的时候,表示使用较大领域中的样本进行预测,训练误差会增大,同时会使模型变得简单,容易导致欠拟合;
 K的取值尽量要取奇数,以保证在计算结果最后会产生一个较多的类别,如果取偶数可能会产生相等的情况,不利于预测。

2.距离的度量:一般使用欧氏距离(欧几里得距离);

3.决策规则:在分类模型中,主要使用多数表决法或者加权多数表决法;在回归模型中,主要使用平均值法或者加权平均值法。

KNN预测规则

1.分类

多数表决法:每个邻近样本的权重是一样的,也就是说最终预测的结果为出现类别最多的那个类。

加权多数表决法:每个邻近样本的权重是不一样的,一般情况下采用权重和距离成反比的方式来计算,也就是说最终预测结果是出现权重最大的那个类别。

2.回归

平均值法:每个邻近样本的权重是一样的,也就是说最终预测的结果为所有邻近样本的目标属性值的均值。

加权平均值法:每个邻近样本的权重是不一样的,一般情况下采用权重和距离成反比的方式来计算,也就是说在计算均值的时候进行加权操作。

KNN算法实现方式

蛮力实现(brute):计算预测样本到所有训练集样本的距离,然后选择最小的k个距离即可得到K个最邻近点。缺点在于当特征数比较多、样本数比较多的时候,算法的执行效率比较低;

KD树(kd tree): KD树算法中,首先是对训练数据进行建模,构建KD树,然后再根据建好的模型来获取邻近样本数据。,除此之外,还有一些从KD-Tree修改后的求解最邻近点的算法,比如: Ball Tree, BBF Tree, MVP Tree等。

python代码

(代码分析写在注释里了)


"""
步骤
1.数据准备
2.计算距离
3.寻找邻居
4.决策分类
"""

import numpy as np
from matplotlib import pyplot as plt

#计算距离公式
def d_man(x, y):#曼哈顿
    d = np.sum(np.abs(x - y))
    return d
def d_euc(x, y):#欧式距离
    d = np.sqrt(np.sum(np.square(x - y)))
    return d


#返回字典
#key函数(itemgetter)获得对象的第一个域的值,定义reverse=True时将按降序排列
#items返回字典dict(key,value)元组对的列表
import operator
def majority_voting(class_count):
    sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)#itemgetter(a)获得第_a_个值,默认从小到大
    return sorted_class_count


def create_data():
    features = np.array(
        [[2.88, 3.05], [3.1, 2.45], [3.05, 2.8], [2.9, 2.7], [2.75, 3.4],
         [3.23, 2.9], [3.2, 3.75], [3.5, 2.9], [3.65, 3.6], [3.35, 3.3]]) #np.array构建二维数组且无需指针
    labels = ['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B']
    return features, labels


def knn_classify(test_data, train_data, labels, k):
    distances = np.array([])  # 创建一个空数组用于存放距离

    for each_data in train_data:  # 使用欧式距离计算数据相似度
        d = d_euc(test_data, each_data)
        distances = np.append(distances, d)  #为原始array添加values
    print(f"距离相似度distances={distances}")
    sorted_distance_index = distances.argsort()  # 获取按距离大小排序后的索引(argsort提取索引)
    sorted_distance = np.sort(distances)    #复制distances数组(对原数组无影响)
    print(f"查看sorted_distance_index{sorted_distance_index}")
    print(f"查看sorted_distance{sorted_distance}")
    r = (sorted_distance[k]+sorted_distance[k-1])/2  # 计算圆的半径

    #计算 'A','B'两类别在范围内的数量
    class_count = {}   #定义一个空字典
    for i in range(k):  #在排好序的数组中挑出距离最短的五个
        vote_label = labels[sorted_distance_index[i]]  #根据索引找到距离对应的类别
        class_count[vote_label] = class_count.get(vote_label, 0) + 1   #!!!!!这步简直了!!我咋就想不到!佩服.jpg!

    final_label = majority_voting(class_count)
    return final_label, r



features, labels =create_data()
test_data = np.array([3.18, 3.15])
final_label, r = knn_classify(test_data, features, labels, 5)  #k=5
print(final_label)
print(r)


#可视化

#极坐标方式表示圆
def circle(r, a, b):  # 为了画出圆,这里采用极坐标的方式对圆进行表示 :x=r*cosθ,y=r*sinθ。
    theta = np.arange(0, 2*np.pi, 0.01)
    x = a+r * np.cos(theta)
    y = b+r * np.sin(theta)
    return x, y


k_circle_x, k_circle_y = circle(r, 3.18, 3.15)

plt.figure(figsize=(5, 5))
plt.xlim((2.4, 3.8))
plt.ylim((2.4, 3.8))
x_feature = list(map(lambda x: x[0], features))  # 返回每个数据的x特征值
y_feature = list(map(lambda y: y[1], features))
plt.scatter(x_feature[:5], y_feature[:5], c="b")  # 在画布上绘画出"A"类标签的数据点
plt.scatter(x_feature[5:], y_feature[5:], c="g")  # 在画布上绘画出"B"类标签的数据点
plt.scatter([3.18], [3.15], c="r", marker="x")  # 待测试点的坐标为 [3.18,3.15]
plt.plot(k_circle_x, k_circle_y)


下面是学习的时候顺手写的笔记,和上面内容差不多
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
距离:https://www.cnblogs.com/soyo/p/6893551.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值