欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

原生python实现knn分类算法

程序员文章站 2024-03-19 16:59:28
...

一、题目分析
K最近邻(k-Nearest Neighbor,KNN)分类算法是最简单的机器学习算法。 KNN算法的指导思想是“近朱者赤,近墨者黑”,由你的邻居来推断出你的类别。本质上,KNN算法就是用距离来衡量样本之间的相似度。
二、算法设计
2.1、计算步骤
1)算距离:给定测试对象,计算它与训练集中的每个对象的距离
2)找邻居:圈定距离最近的k个训练对象,作为测试对象的近邻
3)做分类:根据这k个近邻归属的主要类别,来对测试对象分类
2.2、相似度的衡量
 距离越近应该意味着这两个点属于一个分类的可能性越大。
但,距离不能代表一切,有些数据的相似度衡量并不适合用距离
 相似度衡量方法:欧式距离
2.3、类别的判定
 简单投票法:少数服从多数,近邻中哪个类别的点最多就分为该类。
 加权投票法:根据距离的远近,对近邻的投票进行加权,距离越近则权重越大(权重为距离平方的倒数)
三、源代码

import numpy as np
import operator

1.处理训练数据集
filename:
训练数据文件
return:
returnMat - 处理得到的每一个训练样本的数据集合
returnLabel - 每一个训练样本所属的类别标签集合

def trainingFile2Matrix(filename):
    """
    函数说明:
        处理训练数据集
    :param filename:
        训练数据文件
    :return:
        returnMat - 处理得到的每一个训练样本的数据集合
        returnLabel - 每一个训练样本所属的类别标签集合
    """
    file = open(filename)
    content = file.readlines()

    lineCount = len(content)

    returnMat = np.zeros((lineCount, 4))
    returnLabel = []

    index = 0

    for line in content:
        line = line.strip()
        example = line.split(',')

        returnMat[index, : ] = example[0 : 4]
        index += 1
        returnLabel.append(example[4])

    return returnMat, returnLabel

2.处理测试数据集
filename:
测试数据文件
return:
returnMat - 处理得到的每一个测试样本的数据集合

def testFile2Matrix(filename):
    """
    函数说明:
        处理测试数据集
    :param filename:
        测试数据文件
    :return:
        returnMat - 处理得到的每一个测试样本的数据集合
    """
    file = open(filename)

    content = file.readlines()

    lineCount = len(content)

    returnMat = np.zeros((lineCount, 4))

    index = 0

    for line in content:
        line = line.strip()
        example = line.split(',')
        returnMat[index, : ] = example[0 : 4]
        index += 1

    return returnMat

  1. 计算训练样本和测试样本之间的欧几里德距离
    train_example:
    训练样本的数据
    test_example:
    测试样本的数据
    example_length:
    样本的属性长度
    return:
    distance - 训练样本和测试样本之间的欧几里德距离
def calculateDistance(train_example, test_example, example_length):
    """
    函数说明:
        计算训练样本和测试样本之间的欧几里德距离
    :param train_example:
        训练样本的数据
    :param test_example:
        测试样本的数据
    :param example_length:
        样本的属性长度
    :return:
        distance - 训练样本和测试样本之间的欧几里德距离
    """
    distance = 0.0
    for i in range(example_length):
        distance += pow(train_example[i] - test_example[i], 2)#欧几里得距离

    return distance

4取得与测试样本距离最近的k个训练样本
trainingSet:
训练样本数据集
trainingLabel:
训练样本标签集
test_example:
测试样本
k:
即参数k
return:
kNeighbors - 与测试样本最近的k个训练样本的集合

def get_K_Neighbors(trainingSet, trainingLabel, test_example, k):
    """
    函数说明:
        取得与测试样本距离最近的k个训练样本
    :param trainingSet:
        训练样本数据集
    :param trainingLabel:
        训练样本标签集
    :param test_example:
        测试样本
    :param k:
        即参数k
    :return:
        kNeighbors - 与测试样本最近的k个训练样本的集合
    """
    length = len(test_example)
    distances = []

    for i in range(len(trainingSet)):
        dis = calculateDistance(trainingSet[i], test_example, length)
        distances.append((trainingLabel[i], dis))

    distances.sort(key=operator.itemgetter(1))

    kNeighbors = []
    for i in range(k):
        kNeighbors.append(distances[i][0])

    return kNeighbors

  1. 取得与测试样本距离最近的k个训练样本中的最公共类别
    kNeighbors:
    与测试样本最近的k个训练样本的集合
    return:
    sortedLabel[0][0] - 预测该测试样本所属的类别
def getReasult(kNeighbors):
    """
    函数说明:
        取得与测试样本距离最近的k个训练样本中的最公共类别
    :param kNeighbors:
        与测试样本最近的k个训练样本的集合
    :return:
        sortedLabel[0][0] - 预测该测试样本所属的类别
    """
    classLabel = {}
    for i in range(len(kNeighbors)):
        temp = kNeighbors[i]
        if temp in classLabel:
            classLabel[temp] += 1
        else:
            classLabel[temp] = 1

    sortedLabel = sorted(classLabel.items(), key=operator.itemgetter(1), reverse=True)
    return sortedLabel[0][0]
  1. 计算预测的准确率
    testLabel:
    测试数据所属的真实类别
    predictions:
    预测测试数据所属的类别
    return:
    (cnt / float(len(testLabel))) * 100.0 - 准确率
def getAccuracy(testLabel, predictions):
    """
    函数说明:
        计算预测的准确率
    :param testLabel:
        测试数据所属的真实类别
    :param predictions:
        预测测试数据所属的类别
    :return:
        (cnt / float(len(testLabel))) * 100.0 - 准确率
    """
    cnt = 0
    

    for i in range(len(testLabel)):
        if(testLabel[i] == predictions[i]):
            cnt += 1

    return (cnt / float(len(testLabel))) * 100.0


7.对数据进行归一化
dataSet:
数据集合
return:
normDataSet - 归一化后的数据集合

def getNormolization(dataSet):
    """
    函数说明:
        对数据进行归一化
    :param dataSet:
        数据集合
    :return:
        normDataSet - 归一化后的数据集合
    """
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)

    ranges = maxVals - minVals
    normDataSet = np.zeros(np.shape(dataSet))

    m = dataSet.shape[0]

    normDataSet = dataSet - np.tile(minVals, (m,1))
    normDataSet = normDataSet / np.tile(ranges, (m,1))

    return normDataSet


  1. 将测试结果写入文件
    filename:
    要写入的文件
    resultSet:
    测试结果集合
def write2File(filename, resultSet):
    """
    函数说明:
        将测试结果写入文件
    :param filename:
        要写入的文件
    :param resultSet:
        测试结果集合
    """
    with open(filename, "r", encoding="utf-8") as f_read:
        content = f_read.readlines()

    #print(content)

    index = 0
    length = len(resultSet)


    with open(filename, "w", encoding="utf-8") as f_write:
        for i in range(length):
            str = ''
            temp = content[i].strip('\n')

            str = temp + ',' + resultSet[i] + '\n'
            index += 1

            f_write.write(str)

9.综合调用前面的功能函数,实现KNN算法的所有步骤

def classify():
    """
    函数说明:
        综合调用前面的功能函数,实现KNN算法的所有步骤
    """

    #自定义测试
    trainingMat, trainingLabel = trainingFile2Matrix("train.txt")

    testMat = testFile2Matrix("test.txt")

    norm_trainingMat = getNormolization(trainingMat)
    norm_testMat = getNormolization(testMat)

    #print(norm_trainingMat)
    #print()
    #print(norm_testMat)


    result = []

    for i in range(len(testMat)):
        kNeighbors = get_K_Neighbors(norm_trainingMat, trainingLabel, norm_testMat[i], 3)
        #print(kNeighbors)
        #print()
        result.append(getReasult(kNeighbors))
    print("knn分类结果为:")
    print(result)
    print("长度为:")
    print(len(result))
    
    print("预测准确率:" + str(getAccuracy(result,result)))

    #print()
    write2File("test.txt", result)



if __name__ == "__main__":
    classify()

四、测试及调试
1.测试代码:
trainingMat,trainingLabel=trainingFile2Matrix(“train.txt”)
testMat = testFile2Matrix(“test.txt”)
norm_trainingMat = getNormolization(trainingMat)
norm_testMat = getNormolization(testMat)
print(norm_trainingMat)
print()
print(norm_testMat)
2.测试调试截屏
原生python实现knn分类算法
原生python实现knn分类算法
原生python实现knn分类算法
原生python实现knn分类算法

五、总结
KNN的缺点

1:效率低下,每个数据都需要O(n*m)
2:高度数据相关
3:预测结果不具有可解释性
4: 维数灾难,随着维度的增加,“看似相近”的两个点之间的距离越来越大,解决方法:降维

KNN的优点

1.简单,易于理解,易于实现,无需估计参数,无需训练;
2.适合对稀有事件进行分类;
3.特别适合于多分类问题(multi-modal,对象具有多个类别标签), kNN比SVM的表现要好