1.实验过程省略灰度化处理过程,用已经处理好的txt数据进行训练
3.jpg
from PIL import Image
def imgtotxt(imgfile,txtfile,size = (32,32)):
image_file = Image.open(imgfile).resize(size,Image.LANCZOS).convert('L')
width,height = image_file.size
f = open(txtfile,'w')
ascii_char = '10'
for i in range(height):
pix_char = ''
for j in range(width):
pixe1 = image_file.getpixel((j,i))
pix_char += ascii_char[int(pixe1/128)]
pix_char += '\n'
f.write(pix_char)
f.close()
imgtotxt('3.jpg','3_0.txt')
'''
3_0.txt
00000000000000000000000000000000
00000000000001111100000000000000
00000000111111111111111100000000
00000111111111111111111111000000
00011111111100000111111111100000
00011111000000000000111111110000
00011000000000000000001111111000
00000000000000000000000111111000
00000000000000000000000111111000
00000000000000000000000111111000
00000000000000000000000111111000
00000000000000000000001111110000
00000000000000000000011111110000
00000000000000000000111111100000
00000000000000000111111110000000
00000001111111111111100000000000
00000001111111111111110000000000
00000000111111111111111111000000
00000000000000000000111111110000
00000000000000000000000111111100
00000000000000000000000011111100
00000000000000000000000001111110
00000000000000000000000001111110
00000000000000000000000000111110
00000000000000000000000001111110
00000000000000000000000001111110
00000000000000000000000011111100
00111000000000000000000111111100
00111111100000000000111111111000
00111111111111111111111111100000
00001111111111111111111110000000
00000000011111111111100000000000
'''
2.数据预处理:txt2arry 函数将文本文件转换为 NumPy 数组,每个文件代表一个手写数字的图像,图像大小为 32x32 像素。
3.数据集构建:convert2dataset 函数从指定文件夹中读取所有文件,转换为数据集和标签。数据集中的每个样本都是一个 1x1024 的数组,标签是从文件名中提取的第一个字符。
4.模型训练:使用 KNeighborsClassifier 类训练 KNN 模型。模型参数 n_neighbors=43 表示考虑 43 个最近邻,weights='distance' 表示在投票时考虑距离的权重,p=2 表示使用欧氏距离。
5.模型评估:计算训练集上的准确率,并使用 classification_report 打印测试集的分类报告。
6.错误分析:找到第一个标签为 8 的样本,检查其预测结果,并打印出预测错误的样本。
7.混淆矩阵:使用 confusion_matrix 和 pd.crosstab 打印混淆矩阵,以评估模型的性能。
8.参数调优:测试不同的 k 值(奇数)对模型性能的影响,并绘制训练集和测试集准确率随 k 值变化的图表。
import os
import numpy as np
#将文本文件转换为 NumPy 数组。
def txt2arry(filename):
#创建了一个形状为 (1, 1024) 的全零数组,用于存储转换后的数据
x = np.zeros((1,1024))
f = open(filename)
for i in range(32):
lineStr = f.readline()
for j in range(32):
#将每个字符转换为整数,并存储在数组 x 的相应位置
x[0,32*i+j] = int(lineStr[j])
return x
#从指定文件夹中读取所有文件,转换为数据集和标签。
def convert2dataset(file_path):
#获取指定文件夹中的所有文件名
list_file = os.listdir(file_path)
'''
m 是文件的数量。
datas 是一个形状为 (m, 1024)
的全零数组,用于存储转换后的数据。
labels 是一个空列表,用于存储标签
'''
m = len(list_file)
datas = np.zeros((m,1024))
labels = []
for i in range(m):
#num = int(list_file[i][0]) 从文件名
#中提取第一个字符并转换为整数,作为标签
num = int(list_file[i][0])
labels.append(num)
#调用 txt2arry 函数将文件内容转换为数组,
#并存储在 datas 的相应行中
datas[i,:] = txt2arry(file_path+'\\'+list_file[i])
return datas,labels
x_train,y_train = convert2dataset('trainingDigits')
x_test,y_test = convert2dataset('testDigits')
from sklearn.neighbors import KNeighborsClassifier
#使用 KNeighborsClassifier 训练模型。
knn = KNeighborsClassifier(n_neighbors=43,weights='distance',p=2)
knn.fit(x_train,y_train)
#计算训练集上的准确率。
score = (knn.score(x_train,y_train))
print('pricise = ',score)
#使用 classification_report 打印测试集的分类报告
from sklearn.metrics import classification_report
y_pred = knn.predict(x_test)
print(classification_report(y_test,y_pred))
#找到第一个标签为 8 的样本,检查其预测结果
i = y_test.index(8)
for j in range(91):
if(y_test[i+j] != y_pred[i+j]):
#打印出预测错误的样本
print('{}[{}]->{}'.format(y_test[i+j],j,y_pred[i+j]))
#使用 confusion_matrix 和 pd.crosstab 打印混淆矩阵
import pandas as pd
from sklearn.metrics import confusion_matrix
y_test = np.array(y_test)
cm = confusion_matrix(y_test,y_pred)
cm_df = pd.crosstab(y_test,y_pred,rownames=['真实值'],colnames=['预测值'],margins=True)
print(cm,cm_df,sep='\n')
#测试不同的 k 值(奇数)对模型性能的影响。
#绘制训练集和测试集准确率随 k 值变化的图表
neighbors = []
for i in range(13,45):
if i%2 == 1:
neighbors.append(i)
train_accuracy = np.empty(len(neighbors))
test_accuracy = np.empty(len(neighbors))
for i,k in enumerate(neighbors):
knn = KNeighborsClassifier(n_neighbors=k,weights='distance',p=2)
knn.fit(x_train,y_train)
train_accuracy[i] = round(knn.score(x_train,y_train),2)
test_accuracy[i] = round(knn.score(x_test,y_test),2)
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.title('k值的变化对准确率的影响')
plt.plot(neighbors,train_accuracy,label='训练样本的准确率')
plt.plot(neighbors,test_accuracy,label='测试样本的准确率')
plt.legend()
plt.xlabel('最近邻k字值')
plt.ylabel('准确率值')
plt.show()
#后期可以遍历找出acc最值时k值
#k 代表的是在进行分类决策时考虑的最近邻的数量
'''
E:\平常学习代码包\mechine_learning\knn_num\.venv\Scripts\python.exe E:\平常学习代码包\mechine_learning\knn_num\knn_Num.py
pricise = 1.0
precision recall f1-score support
0 0.99 1.00 0.99 87
1 0.88 0.97 0.92 97
2 0.95 0.96 0.95 92
3 0.95 0.94 0.95 85
4 1.00 0.93 0.96 114
5 1.00 0.94 0.97 108
6 0.97 1.00 0.98 87
7 0.92 1.00 0.96 96
8 0.96 0.86 0.91 91
9 0.91 0.93 0.92 89
accuracy 0.95 946
macro avg 0.95 0.95 0.95 946
weighted avg 0.95 0.95 0.95 946
8[1]->3
8[3]->6
8[13]->2
8[28]->6
8[29]->1
8[30]->1
8[31]->1
8[33]->1
8[40]->1
8[47]->6
8[59]->1
8[62]->1
8[79]->1
[[ 87 0 0 0 0 0 0 0 0 0]
[ 0 94 2 0 0 0 0 1 0 0]
[ 0 1 88 0 0 0 0 2 0 1]
[ 0 0 2 80 0 0 0 0 2 1]
[ 1 2 0 0 106 0 0 3 1 1]
[ 0 0 0 1 0 102 0 0 0 5]
[ 0 0 0 0 0 0 87 0 0 0]
[ 0 0 0 0 0 0 0 96 0 0]
[ 0 8 1 1 0 0 3 0 78 0]
[ 0 2 0 2 0 0 0 2 0 83]]
预测值 0 1 2 3 4 5 6 7 8 9 All
真实值
0 87 0 0 0 0 0 0 0 0 0 87
1 0 94 2 0 0 0 0 1 0 0 97
2 0 1 88 0 0 0 0 2 0 1 92
3 0 0 2 80 0 0 0 0 2 1 85
4 1 2 0 0 106 0 0 3 1 1 114
5 0 0 0 1 0 102 0 0 0 5 108
6 0 0 0 0 0 0 87 0 0 0 87
7 0 0 0 0 0 0 0 96 0 0 96
8 0 8 1 1 0 0 3 0 78 0 91
9 0 2 0 2 0 0 0 2 0 83 89
All 88 107 93 84 106 102 90 104 81 91 946
'''