#机器学习 (3) KNN 算法

文章介绍了KNN算法的基本原理,包括基于K-means聚类后的数据点分类。通过使用欧氏距离作为距离度量,选择最近的K个邻居来预测新样本的标签。给出了一个Python代码示例,展示了如何计算距离、选择最近邻以及更新质心的过程,最终将新数据点正确归类到相应的簇中。
摘要由CSDN通过智能技术生成

KNN算法建立在K-means算法的基础上,即我们已经得到了聚类后的数据点簇后,输入一个新的数据点,将它归为现有的簇中。

KNN算法的步骤如下:

  1. 准备训练数据:收集包含特征和标签的训练数据集。

  2. 选择K值:确定K值,即在预测时考虑最近数据点的数量。K值一般是一个正整数,根据实际问题和数据集的特点进行选择。

  3. 计算距离:对于新样本,计算其与训练数据集中每个样本之间的距离。常用的距离度量方法有欧氏距离(两点间距离公式)、曼哈顿距离等。

  4. 选择最近邻:根据计算的距离,选择与新样本最近的K个邻居

  5. 排序:对于分类问题,通过对这K个邻居的标签进行排序。

  6. 输出预测结果:根据排序结果,选取最高的标签,即为新样本的预测标签。

代码实现:

import numpy as np
import matplotlib.pyplot as plt
import math


def printpoint_add(tpPoints, size, color='b', marker=None):
    plt.scatter(*zip(*[[point[0], point[1], size, color]
                       for point in tpPoints]),
                marker=marker)


def printpoint_show():
    plt.show()


def randpoint(size=0):
    if size == 0:
        return (np.random.randint(0, 10) + np.random.rand(),
                np.random.randint(0, 10) + np.random.rand())
    else:
        point = list()
        for _ in range(size):
            point.append(randpoint())
        return point


def distance(point, centroid):
    return math.sqrt((point[0] - centroid[0])**2 + (point[1] - centroid[1])**2)


#遍历分类的距离,找到距离参数对应的数据类代号
def findClass(case_dist):
    for i in range(countCluster):
        if case_dist in dicDistance[i]:
            dicDistance[i].remove(case_dist)
            return i
    return -1


countCluster = np.random.randint(2, 4)  #簇总数
listCentroid = randpoint(size=countCluster)  #质心点集
dicElement = dict()  #簇代号-->数据点集,实现基于簇序号将数据点聚类
dicDistance = dict()  #簇代号-->新数据点和簇中数据点的欧几里得距离集
listDistance = list()  #全部欧几里得距离集
listPoint = randpoint(size=np.random.randint(100, 300))  #全部数据点集
listColor = ['r', 'b', 'g', 'c', 'm', 'y', 'k', 'w']  #plt颜色列表

count = 100
while count:
    #每次循环都清空原有分类点,以便重新分类
    for i in range(countCluster):
        dicElement[i] = list()

    #以质心为中心,使数据点聚集成簇
    for point in listPoint:
        dist = math.inf
        index = 0

        #遍历质心,找到距离最近的质心序号(index)
        for i, centroid in enumerate(listCentroid):
            newdist = distance(point, centroid)
            if newdist < dist:
                dist = newdist
                index = i

        #数据点入簇
        dicElement[index].append(point)

    #以簇为单位,更新质心位置
    for i, points in dicElement.items():
        if (length := len(points)) == 0: continue
        x, y = 0, 0
        for point in points:
            x += point[0]
            y += point[1]
        x /= length
        y /= length
        listCentroid[i] = (x, y)
    count -= 1

for i, centroid in enumerate(listCentroid):
    printpoint_add([centroid], 120, listColor[i], '*')
    printpoint_add(dicElement[i], 20, listColor[i])

newPoint = randpoint()

for i, points in dicElement.items():
    dicDistance[i] = list()
    for point in points:
        dist = distance(newPoint, point)
        dicDistance[i].append(dist)
        listDistance.append(dist)

listDistance.sort()

K = 50
i = 0
listDistCount = [0 for _ in range(countCluster)]  #对应簇序号的距离命中数
while K:
    if i > len(listDistance) - 1: break
    
    index = findClass(listDistance[i])
    if index == -1:
        i += 1
        continue
    else:
        listDistCount[index] += 1
        i += 1
        K -= 1

maxClusterIndex = listDistCount.index(max(listDistCount))
print('各分类命中次数:', listDistCount)
print('最多命中簇序号:', maxClusterIndex)

printpoint_add([newPoint], 200, listColor[maxClusterIndex], '^')
printpoint_show()

运行效果(三角形即为新数据点,被正确归为绿色簇中):

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值