1 import pandas as pd
2 import numpy as np
3 import matplotlib.pyplot as plt
4 import os
5 from sklearn.neighbors import KNeighborsClassifier # knn分类
6
7
8 def build_data(file_path):
9 """
10 加载并处理数据
11 :param file_path:文件夹路径
12 :return: 数据集
13 """
14 # 获取文件名称
15 file_name_list = os.listdir(file_path)
16 print("file_name_list:\n", file_name_list)
17
18 # 加载每一个文件中的内容
19 # for循环加载
20 # 大数组
21 data_arr = np.zeros(shape=(len(file_name_list), 1025))
22 for file_index, file_name in enumerate(file_name_list):
23 # 获取文件序号 文件名称
24 # print("file_index:", file_index)
25 # print("file_name:", file_name)
26 # 获取每一个文件的文件内容
27 file_content = np.loadtxt(file_path + "/" + file_name, dtype=np.str)
28 # print("file_content:\n", file_content)
29 # 单个样本
30 single_sample_feture = np.zeros(shape=(len(file_content), 32))
31 for file_content_num, file_content_data in enumerate(file_content):
32 # print("file_content_num:", file_content_num)
33 # print("file_content_data:", file_content_data)
34 # 将每一个元素转化 数值类型 0 1 0 1
35 # 法1
36 # li = [int(i) for i in file_content_data]
37 # print(li)
38 # map函数
39 li = list(map(int, file_content_data))
40 # print(li)
41 single_sample_feture[file_content_num, :] = li
42 # print(single_sample_feture)
43 # 将样本的二维数组展开成一维 作为样本的特征值
44 single_data_arr_feature = single_sample_feture.ravel()
45 # 将单个样本的特征值加到data_arr
46 data_arr[file_index, :1024] = single_data_arr_feature
47
48 # 获取目标值
49 target = file_name.split("_")[0]
50
51 # 将目标值添加到数组中
52 data_arr[file_index, 1024] = target
53
54 # print("data_arr:\n",data_arr)
55 # print("data_arr 的形状:\n",data_arr.shape)
56
57 return data_arr
58
59
60 def save_data(file_data, file_name):
61 """
62 保存数据
63 :param file_data: 数据
64 :param file_name: 文件名称
65 :return: None
66 """
67 # 如果data 文件不存在,就创建,如果存在,则不执行
68 if not os.path.exists("./data"):
69 os.makedirs("./data")
70 # 保存文件
71 np.save("./data/" + file_name, file_data)
72
73
74 def load_data():
75 """
76 加载数据
77 :return:train test
78 """
79 train = np.load("./data/train_data.npy")
80 test = np.load("./data/test_data.npy")
81
82 return train, test
83
84
85 def distance(v1, v2):
86 """
87 计算距离
88 :param v1:点1
89 :param v2: 点2
90 :return: 距离dist
91 """
92 # 法1
93 # v1 是矩阵 将矩阵转化数组,再进行降为1维
94 # v1 = v1.A[0]
95 # print(v1)
96 # sum_ = 0
97 # for i in range(v1.shape[0]):
98 # sum_ += (v1[i] - v2[i]) ** 2
99 # dist = np.sqrt(sum_)
100 # print(dist)
101 # 法2
102 dist = np.sqrt(np.sum(np.power((v1 - v2), 2)))
103 return dist
104
105
106 def knn_owns(train, test, k):
107 """
108 knn识别手写字
109 :param train: 训练集
110 :param test: 测试集
111 :param k: 邻居个数
112 :return: 准确率
113 """
114 true_num = 0
115 # 计算每一个测试样本与每一个训练样本的距离
116 for i in range(test.shape[0]):
117 # 构建数组 来保存 每一个测试样本与所有训练样本的距离
118 arr_dist = np.zeros(shape=(train.shape[0], 1))
119 for j in range(train.shape[0]):
120 dist = distance(test[i, :1024], train[j, :1024])
121 arr_dist[j, 0] = dist
122 # print(arr_dist)
123 # 将距离与训练集的目标值 组合起来
124 mutile_arr = np.concatenate((arr_dist, train[:, 1024].reshape((-1, 1))), axis=1)
125 # 因为数组排序不是整个样本一块动---排序---dataframe
126 res_df = pd.DataFrame(data=mutile_arr, columns=["dist", "target"])
127 # print(res_df)
128 # 按照距离进行升序排序
129 y_predict = res_df.sort_values(by="dist")["target"].head(k).mode()[0]
130 # print("y_predict:", y_predict)
131 if test[i, 1024] == y_predict:
132 true_num += 1
133 # 准确率
134 score = true_num / test.shape[0]
135
136 return score
137
138
139 def show_res(score_list, k_list):
140 """
141 结果展示
142 :param score_list: 准确率列表
143 :param k_list: k列表
144 :return: None
145 """
146 # 1、创建画布
147 plt.figure()
148 # 修改RC参数,来让其支持中文
149 plt.rcParams[\'font.sans-serif\'] = \'SimHei\'
150 plt.rcParams[\'axes.unicode_minus\'] = False
151 # 2、绘图
152 plt.plot(k_list, score_list, color=\'r\', linestyle=\':\', linewidth=1.2, marker="*", markersize=7, markerfacecolor=\'b\',
153 markeredgecolor=\'g\')
154 # 增加标题
155 plt.title("随着k的不同,准确率的变化趋势")
156 # 增加横轴、纵轴名称
157 plt.xlabel("k值")
158 plt.ylabel("准确率")
159 # 增加横轴刻度
160 plt.xticks(k_list)
161 # 标注
162 for i, j in zip(k_list, score_list):
163 plt.text(i, j, "%.2f"%j,horizontalalignment=\'center\')
164 # 保存图片
165 plt.savefig("./准确率变化走势图_sklearn.png")
166 # 3、展示
167 plt.show()
168
169
170 def main():
171 """
172 主函数
173 :return:
174 """
175 # # 1、加载并处理数据
176 # train = build_data("./trainingDigits")
177 # test = build_data("./testDigits")
178 #
179 # print("train:\n",train)
180 # print("train的形状:\n",train.shape)
181 #
182 # print("test:\n", test)
183 # print("test的形状:\n", test.shape)
184 #
185 # # 2、保存训练集与测试集数据
186 # save_data(train,"train_data")
187 # save_data(test,"test_data")
188
189 # 1、加载数据
190 train, test = load_data()
191 print("train:\n", train)
192 print("test:\n", test)
193
194 # 2、自实现knn算法
195 score_list = []
196 k_list = [5, 6, 7, 8, 9, 10]
197 # 自实现knn原理识别手写字
198 # for k in k_list:
199 # score = knn_owns(train, test, k)
200 #
201 # score_list.append(score)
202 # print("score_list:\n", score_list)
203
204 # 使用sklearn 中的knn算法进行手写字识别
205 for k in k_list:
206 # (1)初始化算法实例
207 knn = KNeighborsClassifier(n_neighbors=k)
208 # (2) 训练数据
209 knn.fit(train[:, :1024], train[:, 1024])
210 # (3) 进行预测
211 y_predict = knn.predict(test[:, :1024])
212
213 # 获取准确率
214 score = knn.score(test[:, :1024], test[:, 1024])
215
216 print("预测值 y_predict:\n", y_predict)
217 score_list.append(score)
218
219 # 3、结果展示
220 show_res(score_list, k_list)
221
222
223 if __name__ == \'__main__\':
224 main()