knn实现自行车分类
knn实现自行车分类
- 收集数据集
- 编写代码
- 读取数据集
- 分离数据集
- 定义knn分类器
- 单张图片的测试
- 多张图片的测试
- 多个k的预测曲线
- 结果分析
收集数据集
在集大宿舍路边拍摄自行车、电动车和摩托车照片,并对图像进行截取得到数据集。

截取图片后将每张图片大小设定为400*500,按类别存储于不同文件夹中。
编写代码
读取数据集
本实验认为所有通道的所有像素均对预测结果有影响,所以读取时将每张图片的三通道展平为一维向量。由于摩托车数据较少因此不放入数据集中。同时此做法数据量较大,在读取图片后使用归一化减小计算量。
"""读取数据集返回数据和标签读取的图片大小为400*500
"""
def lode_data():data=[]labels=[]for filename in os.listdir(r"../data/cycle"): #listdir的参数是文件夹的路径filenames = '../data/cycle/'+filenameimg = cv2.imread(filenames,1)#归一化img = (img - np.min(img)) / (np.max(img) - np.min(img))data.append(img.flatten())labels.append('cycle')for filename in os.listdir(r"../data/electric_vehicle"): #listdir的参数是文件夹的路径filenames = '../data/electric_vehicle/'+filenameimg = cv2.imread(filenames,1)#归一化img = (img - np.min(img)) / (np.max(img) - np.min(img))data.append(img.flatten())labels.append('electric_vehicle')data = np.array(data)labels = np.array(labels)# print(labels)return data, labels
分离数据集
"""分离训练集和测试集,默认比率为0.75
"""
def separate_dataset(dataset, labels, spearate_rate=0.75):train_data = []train_labels = []test_data = []test_labels = []#随机打乱数据集dataset_tmp = list(range(len(dataset)))random.shuffle(dataset_tmp)train_data_index = dataset_tmp[:int(len(dataset)*spearate_rate)]test_data_index = dataset_tmp[int(len(dataset)*spearate_rate):]for i in train_data_index:train_data.append(dataset[i])train_labels.append(labels[i])for i in test_data_index:test_data.append(dataset[i])test_labels.append(labels[i])train_data = np.array(train_data)train_labels = np.array(train_labels)test_data = np.array(test_data)test_labels = np.array(test_labels)return train_data, train_labels, test_data, test_labels
定义knn分类器
knn是k近邻算法,原理为对输入图片进行预测时,将其与训练集中所有图片计算距离,再选取距离最近的前k个图片中对应标签最多的类别作为预测类别。本次实验距离公式采用2范式也就是欧式距离,将两张图片向量对应位置之差平方求和后取根号作为图片的距离。
d i s t e n c e = ∑ i = 0 n − 1 ( x i − y i ) 2 distence = \sqrt{\sum_{i = 0}^{n - 1}{\left ( x_i-y_i\right )}^2 } distence=i=0∑n−1(xi−yi)2
其中n为向量长度。
"""knn分类器img为预测图像dataset为已有训练集labels为已有标签k为k近邻参数,默认为1
"""
def classify0(img, dataset, labels, k=1):k = int(k)assert k > 0, "k必须为正整数"if len(img.shape) > 1:# 将输入非一维图片转为一维img = img.flatten()diff_mat = np.tile(img, (dataset.shape[0], 1)) - datasetsq_distences = (diff_mat ** 2).sum(axis=1)distences = sq_distences ** 0.5sorted_distences = distences.argsort()classcount={}for i in range(k):vote_label = labels[sorted_distences[i]]classcount[vote_label] = classcount.get(vote_label, 0) + 1sorted_classcount = sorted(classcount.items(), key = operator.itemgetter(1), reverse = True)return sorted_classcount[0][0]
单张图片的测试
当k=3时的预测结果
data, labels = lode_data()
train_data, train_labels, test_data, test_labels = separate_dataset(data, labels)a = classify0(test_data[0], train_data, train_labels, 3)
print(a)
print(test_labels[0])

可以看出预测结果出错,但是想要看分类器效果还需要对所有测试集图片进行测试
多张图片的测试
定义函数
"""统计预测正确的图片数量
"""
def test_all(train_data, train_labels, test_data, test_labels, k=1):right = 0for i in range(len(test_data)):if classify0(test_data[i], train_data, train_labels, k) == test_labels[i]:right+=1return right
预测结果
data, labels = lode_data()
train_data, train_labels, test_data, test_labels = separate_dataset(data, labels)right = test_all(train_data, train_labels, test_data, test_labels, 1)
accuracy = right/len(test_labels)
print(f"accuracy = {accuracy}")

精度等于0.5说明此时的k对应的预测结果还是较差的
多个k的预测曲线
编写代码
data, labels = lode_data()
train_data, train_labels, test_data, test_labels = separate_dataset(data, labels)
accuracy_all = []for i in tqdm(range(len(train_data) - 1)):right = test_all(train_data, train_labels, test_data, test_labels, i + 1)accuracy = right/len(test_labels)accuracy_all.append(accuracy)plt.plot(range(len(train_data) - 1),accuracy_all)
plt.show()

结果分析
对于k较小时由于图片背景相似又类别不同导致准确率不稳定,在k等于22时准确率达到最大值,此时图片数量增大,背景对投票结果的影响变小,因此准确率较高。在k>=30时,由于电动车本身站数据集比重较高,导致投票结果为电动车可能性更大,使得结果准确率趋于稳定。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
