02--机器学习之最近邻规则分类(KNN)

本文介绍了KNN算法的基本原理,包括距离度量方法、算法步骤及优缺点,并通过Python代码示例展示了如何使用sklearn库实现KNN算法。此外,还提供了一个从零开始实现KNN算法的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.例子

这里写图片描述
实例,两个特征
对例子建模
这里写图片描述

举例:
这里写图片描述
上面这个图中,把小手指的这个豆子归为哪个类呢?knn的做法是看它的邻居们是什么类,然后把它归为和邻居一样的类

2.算法详述
1)步骤
为了判断未知实例的类别,以所有已知类别的实例作为参照
选择参数K(一般都选择奇数)
计算未知实例与所有已知实例的距离
选择最近K个已知实例
根据少数服从多数的投票法则(majority-voting),让未知实例归类为K个最邻近样本中最多树的类别

2)细节
关于距离的衡量方法:
1.Euclidean Distance
这里写图片描述
3.算法优缺点
1)算法优点:
简单
易于理解
容易实现
通过对K的选择可具备丢噪音数据的健壮性
2)算法缺点
这里写图片描述
需要大量空间存储所有已知实例
算法复杂度高(需要比较所有已知实例与要分类的实例)
当其样本分布不平衡时,比如其中一类样本过大(实例数量过多)占主导的时候,新的未知实例容易被归类为这个主导样本,因为这类样本实例的数量过大,但这个新的未知实例实际并没有接近目标样本

3)改进算法
考虑距离,根据距离加上权重
比如:1/d(d:距离)
离未知实例近的,则权重就大

4.介绍一种数据集
虹膜 iris
这里写图片描述
是一种花,这个数据集中一共有150个实例
萼片长度,萼片宽度,花瓣长度,花瓣宽度(sepal length,sepal width,petal length and petal width)
类别:3中label
Iris setosa, Iris versicolor, Iris virginica

这个数据集相当于有150个样本(150行),每个样本有4个特征,一个label。相当于有5列

python代码:调用sklearn库中的模块

"""调用库实现"""
from sklearn import neighbors #knn这个分类器包含在neighbors这个模块中
from sklearn import datasets #我们用到的Iris这个数据集包含在datasets这个模块中,所以要导入这个模块


knn = neighbors.KNeighborsClassifier() #将这个分类器复制给定义的变量knn
iris = datasets.load_iris() #加载要用到的数据集

print(iris) #把这个数据集打印出来

knn.fit(iris.data,iris.target) #fit函数  建立模型,然后传入参数(特征值,标签)

predictLabel = knn.predict([[0.1,0.2,0.3,0.4]])#根据建好的模型来预测新的实例

print(predictLabel)

python代码:自己实现各个模块

import csv  #加载csv格式的文件用的
import random
import math  #计算距离
import operator

def loadDataset(filename,split,trainingSet=[],testSet=[]):#加载数据的函数(文件名称,split将数据集分成两部分,一个训练集,一个测试集)
    with open(filename,'r') as csvfile:#把文件导入成csv格式的文件
        lines = csv.reader(csvfile)#读取所有的行
        dataset = list(lines)#将所有行转化成list,并赋值给定义的变量名dataset
        for x in range(len(dataset) - 1):
            for y in range(4):
                dataset[x][y] = float(dataset[x][y]) #把dataset中的数据转换成float格式
            if random.random() < split: #如果产生的随机数小于split,那么就将这一行的数据加入到训练集中
                trainingSet.append(dataset[x])
            else:#如果产生的随机数大于split,那么就将这一行的数据加入到测试集中
                testSet.append(dataset[x])


def euclideanDistance(instancel,instance2,length):#计算距离的函数(实例1(有可能是多维),实例2(有可能是多维),维度变量)
    distance = 0 #初始化distance为0
    for x in range(length):#对于length维度的实例,分别计算每个值得平方((x1-y1)^2 + (x2-y2)^2 + ...+(xlength - ylength)^2)
        distance +=pow((instancel[x] - instance2[x]),2)
    return math.sqrt(distance) #对distance开平发


def getNeighbors(trainingSet,testInstance,k):#返回最近的K个邻居的函数
    distances = [] #定义一个空的容器,用来装各个距离
    length = len(testInstance) - 1 #要测试实例的维度
    for x in range(len(trainingSet)): #对训练集中的每一个样本,计算未知实例到每个样本的距离
        dist = euclideanDistance(testInstance,trainingSet[x],length)
        distances.append((trainingSet[x],dist))#把训练集中每个样本与未知实例的距离算出后加入到定义的distance容器中
    distances.sort(key=operator.itemgetter(1))#用sort函数把容器中的距离按从小到大排列
    neighbors = []
    for x in range(k):#返回容器中距离最近的K个邻居
        neighbors.append(distances[x][0])
    return neighbors


def getResponse(neighbors):#在返回的个邻居中,根据少数服从多数进行归类
    classVotes = {}
    for x in range(len(neighbors)):#对各个邻居进行归类,
        response = neighbors[x][-1]
        if response in classVotes:
            classVotes[response] += 1
        else:
            classVotes[response] = 1
    sortedVotes = sorted(classVotes.items(),key=operator.itemgetter(1),reverse=True)#对每个类中同类邻居的个数按降序排列
    return sortedVotes[0][0]#返回第一个值


def getAccuracy(testSet,predictions): #计算一下准确率,比较一个预测的值和真实值
    correct = 0
    for x in range(len(testSet)):
        if testSet[x][-1] ==predictions[x]:#[-1]代表最后一个值  如果测试集中的label == 预测出来的label
            correct += 1 #正确的个数加1
    return (correct/float(len(testSet))) * 100.0  #返回计算的正确率

def main():

    #prepare data
    trainingSet = [] #创建空的训练集
    testSet = [] #创建空的测试集
    split = 0.67 #将加载加的数据集分为测试集和训练集的标准定为0.67(把2/3的数据集分为训练集,把1/3的数据集分为测试集)
    #这里的r 是将后面的整个字符串当做路径,而忽略其中的特殊符号,比如\n这种转义符就能忽略掉
    loadDataset(r'J:\python_program\machine_learning\KNN\iris.txt',split,trainingSet,testSet)
    print("Train set: " + repr(len(trainingSet)))
    print("Test set: " + repr(len(testSet)))

    #generate predictions
    predictions = []
    k = 3
    for x in range(len(testSet)):
        neighbors = getNeighbors(trainingSet,testSet[x],k)
        result = getResponse(neighbors)
        predictions.append(result)
        print("> predicted= " + repr(result) + ",actual = " +repr(testSet[x][-1]))
    accuracy = getAccuracy(testSet,predictions)
    print("Accuracy: " + repr(accuracy) + "%")

main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值