knn实现自行车分类

knn实现自行车分类

  • 收集数据集
  • 编写代码
    • 读取数据集
    • 分离数据集
    • 定义knn分类器
    • 单张图片的测试
    • 多张图片的测试
    • 多个k的预测曲线
  • 结果分析

收集数据集

在集大宿舍路边拍摄自行车、电动车和摩托车照片,并对图像进行截取得到数据集。
knn实现自行车分类_第1张图片
截取图片后将每张图片大小设定为400*500,按类别存储于不同文件夹中。

编写代码

读取数据集

本实验认为所有通道的所有像素均对预测结果有影响,所以读取时将每张图片的三通道展平为一维向量。由于摩托车数据较少因此不放入数据集中。同时此做法数据量较大,在读取图片后使用归一化减小计算量。

"""
    读取数据集返回数据和标签
    读取的图片大小为400*500
"""
def lode_data():
    data=[]
    labels=[]
    for filename in os.listdir(r"../data/cycle"):              #listdir的参数是文件夹的路径
        filenames = '../data/cycle/'+filename
        
        img = 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/'+filename
        
        img = 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=0n1(xiyi)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)) - dataset
    sq_distences = (diff_mat ** 2).sum(axis=1)
    distences = sq_distences ** 0.5
    sorted_distences = distences.argsort()
    classcount={}
    for i in range(k):
        vote_label = labels[sorted_distences[i]]
        classcount[vote_label] = classcount.get(vote_label, 0) + 1
    sorted_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 = 0

    for i in range(len(test_data)):
        if classify0(test_data[i], train_data, train_labels, k) == test_labels[i]:
            right+=1

    return 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()

knn实现自行车分类_第2张图片

结果分析

对于k较小时由于图片背景相似又类别不同导致准确率不稳定,在k等于22时准确率达到最大值,此时图片数量增大,背景对投票结果的影响变小,因此准确率较高。在k>=30时,由于电动车本身站数据集比重较高,导致投票结果为电动车可能性更大,使得结果准确率趋于稳定。

你可能感兴趣的:(机器学习,分类,python)