实现KNN算法

基本要求:编程实现kNN算法;给出在不同k值(1,3,5)情况下,kNN算法对⼿写数字的识别精度

KNN算法是机器学习算法中最基础、最简单的算法之一。它既能用于分类,也能用于回归。KNN通过测量不同特征值之间的距离来进行分类。

KNN算法的思想非常简单:对于任意n维输入向量,分别对应于特征空间中的一个点,输出为该特征向量所对应的类别标签或预测值。

KNN算法是一种非常特别的机器学习算法,因为它没有一般意义上的学习过程。它的工作原理是利用训练数据对特征向量空间进行划分,并将划分结果作为最终算法模型。存在一个样本数据集合,也称作训练样本集,并且样本集中的每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。

输入没有标签的数据后,将这个没有标签的数据的每个特征与样本集中的数据对应的特征进行比较,然后提取样本中特征最相近的数据(最近邻)的分类标签。

一般而言,我们只选择样本数据集中前k个最相似的数据,这就是KNN算法中K的由来,通常k是不大于20的整数。最后,选择k个最相似数据中出现次数最多的类别,作为新数据的分类。

本次实验中,我们将编程实现kNN算法;给出在不同k值(1,3,5)情况下,kNN算
法对⼿写数字的识别精度,同时在结果与耗时两方面与 Python 机器学习包中的kNN分类结果进⾏对⽐,得出对应的结论。

数据预处理代码如下所示:

np.set_printoptions(threshold=2000)
data_train=pd.read_csv("第一次实验/semeion_train.csv",encoding="utf-8",header=None)
x_train=data_train[0]

Images_train = np.zeros([1115, 256])
Labels_train = np.zeros([1115, 10])
nums_train=np.zeros([1115],dtype=int)

for i in range(1115):#处理行数据进行分割,分别分割到Image和Labels数组中
    x_train[i]=x_train[i].rstrip(' \n')
    currentLine=x_train[i].split(' ')
    Images_train[i][:]=currentLine[:256]
    Labels_train[i][:]=currentLine[256:]

for i in range(1115):#存放具体数值
    for j in range(10):
        if Labels_train[i][j]==1:
            nums_train[i]=j
            break

手写KNN算法代码如下所示:

import numpy as np
import pandas as pd
class KNN:#使用KNN进行算法实现
    def __init__(self, k):
        self.k = k

    def fit(self, X, y):
        self.X = np.asarray(X) #转换为ndarray类型
        self.y = np.asarray(y)

    def predict(self, X):
        X = np.asarray(X)
        result = []
        for x in X:
            dis = np.sqrt(np.sum((x-self.X)**2, axis=1)) # 对于测试机的每隔一个样本,一次与训练集的所有数据求欧氏距离
            index = dis.argsort()# 返回排序结果的下标
            index = index[:self.k] # 截取前K个数据,k为近零样本的数量
            count = np.bincount(self.y[index]) # 返回数组中每个整数元素出现次数,元素必须是非负整数
            result.append(count.argmax()) # 返回ndarray中值最大的元素所对应的索引,就是出现次数最多的索引,也就是我们判定的类别(最终结果)
        return np.asarray(result)

对样本进行训练与测试的代码如下:

knn1=KNN(k=1)
knn1.fit(Images_train,nums_train)
Images_predict1=knn1.predict(Images_test)
accuracy1=0
for i in range(478):
    if Images_predict1[i]==nums_test[i]:
        accuracy1+=1

print("n_neignbors=1时准确率为:",accuracy1/478)

测试算法消耗时间的代码如下:

from time import time
t1 = time()#开始时间
...
t2=time()#结束时间
print("消耗时间为:",t2-t1,"s")

算法结果如下所示:

n_neignbors=1时准确率为: 0.8556485355648535
n_neignbors=3时准确率为: 0.8389121338912134
n_neignbors=5时准确率为: 0.8556485355648535
消耗时间为: 5.14014458656311 s

中级要求:与 Python 机器学习包中的kNN分类结果进⾏对⽐

调用KNN包的代码如下:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier#调用KNN包

knn1=KNeighborsClassifier(n_neighbors=1)#调用KNN包进行学习
knn1.fit(Images_train,nums_train)
Images_predict1=knn1.predict(Images_test)
score1 = knn1.score(Images_test, nums_test)

算法结果如下所示:

n_neignbors=1时准确率为: 0.8556485355648535
n_neignbors=3时准确率为: 0.8410041841004184
n_neignbors=5时准确率为: 0.8389121338912134
消耗时间为: 3.1720590591430664 s

通过上述两组实验对比,可以看出,调用KNN包与手写KNN所得出的手写数字识别精度大体差异不大,但是对比两者运行时间,可以看出,调用KNN机器学习包后,运行程序所消耗的时间比不调用包更少,随着训练集与测试集的数量级的增大,运行时间上的差异会更加显著。