k-近邻算法(k-NN)及其Python实现

本文介绍k-近邻算法(k-NN)的基本原理和步骤,并通过Python实现算法,利用Iris数据集进行分类预测。文章涵盖算法流程、优缺点及改进方法,最后通过实验验证了算法的有效性。

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

k-近邻算法(k-NN)及其Python实现

  • 算法思想:
      给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(K个邻居), 这K个实例的多数属于某个类,就把该输入实例分类到这个类中。

  • 算法流程:

    1. 计算已知类别数据集中的点与当前点之间的距离;
    2. 按照距离递增次序排序;
    3. 选取与当前点距离最小的k个点;
    4. 确定前k个点所在类别的出现频率;
    5. 返回前k个点出现频率最高的类别作为当前点的预测分类。
  • 优缺点:
    优点:简单易懂;
    缺点:时间复杂度高、k值的选取需要专家经验

  • 改进方法:
      降低k-NN时间复杂度,提高搜索效率,可以通过KD-Tree进行优化,详细介绍可以参考KD-Tree详解


from numpy import *
import operator

#文件读取
def file2matrix(filename, attribute_num):   #传入参数:文件名,属性个数
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)    #统计数据集行数(样本个数)
    returnMat = zeros((numberOfLines, attribute_num))
    classLabelVector = []   #分类标签
    index = 0
    for line in arrayOLines:
        line = line.strip() #strip() 删除字符串中的'\n'
        listFromLine = line.split(',') #将一个字符串分裂成多个字符串组成的列表,不带参数时以空格进行分割,当代参数时,以该参数进行分割
        returnMat[index, : ] = listFromLine[0:attribute_num]    #读取数据对象属性值
        classLabelVector.append(listFromLine[-1])   #读取分类信息
        index += 1
    return returnMat, classLabelVector  #返回值:数据集,分类信息

#数据归一化
def autoNorm(dataSet):  #传入参数:数据集
    minVals = dataSet.min(0)    #数据集每一行的最小值 1Xattribute_num
    maxVals = dataSet.max(0)    #数据集每一行的最大值 1Xattribute_num
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]    #统计数据集行数
    normDataSet = dataSet -tile(minVals, (m, 1))
    normDataSet = normDataSet/tile(ranges, (m, 1))
    return normDataSet
    #return normDataSet, ranges, minVals #返回值:归一化后数据集,每列的最大值与最小的差值,每列的最小值

#k-NN算法
def classify0(testData, trainDataSet, labels, k): #传入参数:测试样本,训练样本数据集,分类标签,k-近邻中的k值
    dataSetSize = trainDataSet.shape[0] #统计训练样本数据集行数
    diffMat = tile(testData, (dataSetSize, 1)) - trainDataSet   #对应属性值求差    #欧式距离计算测试样本与所有训练样本的距离
    sqDiffMat = diffMat**2  #差值平方
    sqDistances = sqDiffMat.sum(axis=1) #对每一行求和
    distance = sqDistances**0.5 #开根号    #得到测试样本与所有训练样本的欧式距离
    sortedDistIndicies = distance.argsort() #测试样本与训练样本的距离按照升序排列
    classCount = {}
    for i in range (k): #选择与测试样本距离最小的k个训练样本点
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1  #统计类标签出现的个数
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) #reverse参数是一个bool变量,表示升序还是降序排列,默认为false(升序排列),定义为True时将按降序排列。
    return sortedClassCount[0][0]   #返回第一个值,即为出现次数最多的类标签

#测试
def datingClassTest():
    hoRatio= 0.3    #原始数据集中,选取前30%作为待测样本,选取后70%作为训练样本
    attribute_num = 4   #数据集样本点属性个数
    k = 10  #k-NN,参数k,距离待测样本最近的k个样本点
    oriDataSet, classLable = file2matrix('iris.txt', attribute_num) #读取原始数据集,以及分类标签
    normDataSet = autoNorm(oriDataSet)  #对数据集进行归一化处理
    m = normDataSet.shape[0]
    beginTestDataSet = int(m*hoRatio)   #原始数据集中,选取前30%作为待测样本,选取后70%作为训练样本
    errorCount = 0.0    #统计分类错误率
    for i in range(beginTestDataSet):
        classifierResult = classify0(normDataSet[i, :], normDataSet[beginTestDataSet:m, :], classLable[beginTestDataSet:m], k)
        print "the classifier came back with: %s, the real answer is %s" %(classifierResult, classLable[i])
        if (classifierResult!=classLable[i]):
            errorCount += 1.0
    print "the total error rate is: %f" %(errorCount/float(beginTestDataSet))
    #return errorCount/float(beginTestDataSet)

def main():
    datingClassTest()
if __name__ == '__main__':
     main()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值