KNN算法手写字识别案例

实验前准备如下 

手写字分别存储在两个文件中,一个是训练集文件,一个是测试集文件。

两个文件夹下的txt文件命名格式是,下划线前面的数字代表文本内存储的文字内容,下划线后面的数字代表是第几个

如:1_12.txt代表文件内存储的内容为手写字1,这是存储手写字1的第12个文件。

本实验中K值与预测准确率的关系如下图

实现代码如下

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import os
from sklearn.neighbors  import KNeighborsClassifier


def build_data(dir_name):
    """
    构建数据
    :param dir_name: 指定传入文件夹名称
    :return: 构建好的数据
    """
    # 获取文件名列表
    file_name_list = os.listdir(dir_name + "/")
    print("获取到的文件名列表:\n", file_name_list)
    # 进行读取文件

    data = np.zeros(shape=(len(file_name_list), 1025))

    # 循环读取文件
    for file_index, file_name in enumerate(file_name_list):
        # file_index  文本名称所对应的下标
        # file_name  文本名称
        # 加载数据
        file_data = np.loadtxt(dir_name + "/" + file_name, dtype=np.str)

        # 构建一个列表
        arr = []
        for file_data_index, file_data_content in enumerate(file_data):
            # print(file_data_content)
            # print("*"*80)
            # 将 每一个元素转化为一个int 类型的列表
            arr_sigle_list = [int(tmp) for tmp in file_data_content]
            # print(arr)
            # 把每个元素添加到列表中
            arr.append(arr_sigle_list)

        # print(arr)
        # 将一个样本转化为数组
        arr_single_sample = np.array(arr)
        # print(arr_single_sample)
        # np.savetxt("./hh.txt",arr_single_sample,fmt="%d")
        # 将二维数组展开为一维---特征值
        arr_single_sample = arr_single_sample.ravel()
        # print(arr_single_sample)
        # 目标值
        label = int(file_name[0])
        # print(res)
        # print(arr_single_sample.shape)
        # 将一个 完整的样本拼接起来,组成完整的样本
        arr_single_sample = np.concatenate((arr_single_sample, [label]), axis=0)

        # print(arr_single_sample)
        # print(arr_single_sample.shape)

        data[file_index, :] = arr_single_sample

    # print(data)
    return data


def save_data(file_name, data):
    """
    保存文件
    :param file_name: 保存的文件名称
    :param data: 保存的数组
    :return: None
    """
    if not os.path.exists("./data/"):
        os.makedirs("./data/")

    np.save("./data/" + file_name, data)


def load_data(file_name):
    """
    加载数据
    :param file_name:文件路径+ 名称
    :return: 数据
    """
    #是否允许读取pickled对象
    data = np.load(file_name, allow_pickle=True)

    return data
def  show_res(k_list,score_list):


    #进行结果可视化
    # 1、创建画布
    plt.figure()
    # 默认不支持中文,需要配置RC 参数
    plt.rcParams['font.sans-serif']='SimHei'
    # 设置字体之后不支持负号,需要去设置RC参数更改编码
    plt.rcParams['axes.unicode_minus']=False
    # 2、绘图
    x = np.array(k_list)
    y = np.array(score_list)

    plt.plot(x,y)

    plt.title("k与准确率的关系走势图")
    plt.xlabel("k值")
    plt.ylabel("准确率")
    # plt.savefig("./k值对准确率的影响.png")
    # 3、展示

    plt.show()
def main():

    train = load_data("./data/train_data.npy")
    test = load_data("./data/test_data.npy")

    train = pd.DataFrame(train)
    test = pd.DataFrame(test)

    k_list = [5,6,7,8,9,10]
    score_list = []
    for k in k_list:
        knn = KNeighborsClassifier(n_neighbors=k)
        #训练数据
        knn.fit(train.iloc[:,:-1].values,train.iloc[:,-1].values)
        # 进行预测
        y_predict = knn.predict(test.iloc[:,:-1].values)

        # 可以获取准确率
        score = knn.score(test.iloc[:,:-1].values,test.iloc[:,-1].values)

        score_list.append(score)

    print(score_list)
    show_res(k_list,score_list)
if __name__ == '__main__':
    main()

 

自实现的代码如下

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import os
from sklearn.neighbors  import KNeighborsClassifier


def build_data(dir_name):
    """
    构建数据
    :param dir_name: 指定传入文件夹名称
    :return: 构建好的数据
    """
    # 获取文件名列表
    file_name_list = os.listdir(dir_name + "/")
    print("获取到的文件名列表:\n", file_name_list)
    # 进行读取文件

    data = np.zeros(shape=(len(file_name_list), 1025))

    # 循环读取文件
    for file_index, file_name in enumerate(file_name_list):
        # file_index  文本名称所对应的下标
        # file_name  文本名称
        # 加载数据
        file_data = np.loadtxt(dir_name + "/" + file_name, dtype=np.str)

        # 构建一个列表
        arr = []
        for file_data_index, file_data_content in enumerate(file_data):
            # print(file_data_content)
            # print("*"*80)
            # 将 每一个元素转化为一个int 类型的列表
            arr_sigle_list = [int(tmp) for tmp in file_data_content]
            # print(arr)
            # 把每个元素添加到列表中
            arr.append(arr_sigle_list)

        # print(arr)
        # 将一个样本转化为数组
        arr_single_sample = np.array(arr)
        # print(arr_single_sample)
        # np.savetxt("./hh.txt",arr_single_sample,fmt="%d")
        # 将二维数组展开为一维---特征值
        arr_single_sample = arr_single_sample.ravel()
        # print(arr_single_sample)
        # 目标值
        label = int(file_name[0])
        # print(res)
        # print(arr_single_sample.shape)
        # 将一个 完整的样本拼接起来,组成完整的样本
        arr_single_sample = np.concatenate((arr_single_sample, [label]), axis=0)

        # print(arr_single_sample)
        # print(arr_single_sample.shape)

        data[file_index, :] = arr_single_sample

    # print(data)
    return data


def save_data(file_name, data):
    """
    保存文件
    :param file_name: 保存的文件名称
    :param data: 保存的数组
    :return: None
    """
    if not os.path.exists("./data/"):
        os.makedirs("./data/")

    np.save("./data/" + file_name, data)


def load_data(file_name):
    """
    加载数据
    :param file_name:文件路径+ 名称
    :return: 数据
    """
    #是否允许读取pickled对象
    data = np.load(file_name, allow_pickle=True)

    return data


def distance(v1, v2):
    """
    计算距离
    :param v1: 点1
    :param v2: 点2
    :return: 距离
    """
    dist = np.sqrt(np.sum(np.power((v1 - v2), 2)))

    return dist


def knn_owns(train, test, k):
    """
    自定knn算法实现手写字识别
    :param train: 训练集数据
    :param test: 测试集数据
    :param k: 邻居个数
    :return: 准确率
    """
    # 设置计数器
    true_num = 0
    # 获取训练集的特征值 目标值
    train_x = train.iloc[:, 0:1024].values
    # print("train_x的shape:\n",train_x.shape)
    train_y = train.iloc[:, 1024].values
    # 获取测试集的特征值 目标值
    test_x = test.iloc[:, 0:1024].values
    # print("test_x的shape:\n",test_x.shape)

    test_y = test.iloc[:,1024].values
    # 计算每一个测试样本特征与每一个训练样本特征的距离
    for i in range(test.shape[0]):  # 循环每一个 测试样本
        for j in range(train.shape[0]):
            # 计算距离
            dist = distance(test_x[i,:],train_x[j,:])
            train.loc[j,'dist'] = dist

        res = train.sort_values(by='dist')

        mode = res.iloc[:,-2][:k].mode()[0]
        print(mode)

        if mode == test_y[i]:
            true_num  += 1
        # print(test_y)

    score =  true_num / test.shape[0]

    print(score)
    return  score

def  show_res(k_list,score_list):


    #进行结果可视化
    # 1、创建画布
    plt.figure()
    # 默认不支持中文,需要配置RC 参数
    plt.rcParams['font.sans-serif']='SimHei'
    # 设置字体之后不支持负号,需要去设置RC参数更改编码
    plt.rcParams['axes.unicode_minus']=False
    # 2、绘图
    x = np.array(k_list)
    y = np.array(score_list)

    plt.plot(x,y)

    plt.title("k与准确率的关系走势图")
    plt.xlabel("k值")
    plt.ylabel("准确率")
    # plt.savefig("./k值对准确率的影响.png")
    # 3、展示

    plt.show()



# train_data  = build_data("./trainingDigits")
# test_data  = build_data("./testDigits")
#
# save_data("train_data",train_data)
# save_data("test_data",test_data)

def  main():
    """
    主函数
    :return: None
    """
    # 加载数据
    train = load_data("./data/train_data.npy")
    test = load_data("./data/test_data.npy")

    train = pd.DataFrame(train)
    test = pd.DataFrame(test)

    # print(train)
    # print("*"*80)
    # print(test)
    k_list = [5]
    score_list = []
    for k in k_list:
        score = knn_owns(train, test, k)
        score_list.append(score)
        # knn = KNeighborsClassifier(n_neighbors=k)
        # #训练数据
        # knn.fit(train.iloc[:,:-1].values,train.iloc[:,-1].values)
        # # 进行预测
        # y_predict = knn.predict(test.iloc[:,:-1].values)
        #
        # # 可以获取准确率
        # score = knn.score(test.iloc[:,:-1].values,test.iloc[:,-1].values)

        score_list.append(score)
    print(score_list)






if __name__ == '__main__':
    main()






 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值