原生python实现knn分类算法

1 题目分析

原生python实现knn分类算法:
最近邻(k-Nearest Neighbor,KNN)的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。KNN算法不仅可以用于分类,还可以用于回归。通过找出一个样本的k个最近邻居,将这些邻居的属性的平均值赋给该样本,就可以得到该样本的属性。

2 算法设计

  1. 首先处理得到每一个训练样本的数据集合和每一个训练样本所属的类别标签集合,再得到每一个测试样本的数据集合
  2. 然后计算训练样本和测试样本之间的欧几里得距离
  3. 取得与测试样本距离最近的k个训练样本集合,预测该测试样本所属的类别
  4. 计算预测的准确率

3 源代码

import numpy as np
import operator

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


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



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

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


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]

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


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

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)


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.调试
在这里插入图片描述
在这里插入图片描述
2.运行结果及预测精确度
在这里插入图片描述
在这里插入图片描述

五 总结

经过此次knn鸢尾花分类算法的编写,我初步了解了机器学习。并且了解道knn算法的核心思想是要想确定测试样本属于哪一类,就先寻找所有训练样本中与该测试样本“距离”最近的前K个样本,然后判断这K个样本中大部分所属的类型,就认为是该测试样本的类型。根据与其最近的k个样本的类型决定其自身的类型。因此K的确定和测算距离的方式是影响样本最终分类准确率的重要因素。本次我使用的是测量欧几里得的距离,优点在于易于理解,实现简单,无需估计参数,无需训练。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值