实验前准备如下
手写字分别存储在两个文件中,一个是训练集文件,一个是测试集文件。
两个文件夹下的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()