K-近邻算法

本文介绍了K-近邻算法的基本概念,如何在Python中准备数据,包括从文本文件中解析图像和标签,以及如何通过KNN算法进行猫狗图片分类。还讨论了常见错误及解决策略,如图像尺寸问题和文件路径处理。
摘要由CSDN通过智能技术生成

目录

1.k-近邻算法概述

1.1准备:使用Python导入数据

1.2从文本文件中解析数据

2.实例:使用K-近邻算法实现猫狗分类

2.1准备数据:从文本文件中解析数据

2.2分析数据:使用Matplotlib创建散点图

2.3效果图展示

3.常见错误及解决思路

1.k-近邻算法概述

KNN(K-Nearest Neighbor)算法是机器学习算法中最基础、最简单的算法之一。它既能用于分类,也能用于回归。KNN通过测量不同特征值之间的距离来进行分类。KNN算法的核心思想是:在已知训练集数据及其标签的情况下,对于一个新输入的测试数据,算法会在训练集中找到与这个测试数据最相似的K个邻居,然后根据这K个邻居的类别来决定测试数据的类别。

具体来说,算法的步骤包括:

  1. 计算距离:计算测试数据与训练集中每个数据点之间的距离。
  2. 选择邻居:按照距离大小对训练数据进行排序,选择距离最小的K个数据点作为邻居。
  3. 投票决策:统计这K个邻居中各个类别的出现频率,频率最高的类别即为测试数据的预测分类。

此过程中我们计算距离需要运用到欧式距离公式,计算两个向量点xA和xB之间的距离:d=\sqrt{(xA0-xB0)^{2}+(xA1-xB1)^{2}}

亦或者,也可以采用曼哈顿距离:

d = \left | x1-x2 \right |+\left | y1-y2 \right |

而后,我们通过选定的k值。将输入的数据通过计算与其它点之间的距离按从小到大排序,选定k个值,计算这k个值里面各类别出现的频率,将频率最高的类别复制给输入的数据作为其标签。

该算法的优点为:

        (1)简单易用;

        (2)模型训练时间快(惰性模型,不需要对数据作出任何的假设,完全根据数据决定);

        (3)预测效果好;

        (4)对异常值不敏感。

该算法的缺点为:

        (1)计算量较大,预测阶段可能较慢;

        (2)对内存要求高,该算法存储了所有训练数据;

        (3)对不相关的功能和数据规模敏感。

1.1准备:使用Python导入数据

首先我们需要去寻找数据集,并将数据集下载到本地。常见的免费数据集下载地址有:https://www.kaggle.com/datasets

https://tianchi.aliyun.com

本次实验我是从kaggle中下载了猫狗的数据集,其数据集中准备了测试集、训练集、验证集的图片文件夹,以及文本(文本中存放了图片的数据和标签)。

在进行导入数据前,我们需要导入一些必要的库,以用来后面进行数据的处理。(这仅是部分,若有需要可以按自己的代码补充相对应的库)

import os
import cv2
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
from PIL import Image
import matplotlib.pyplot as plt

导入数据我们一般可以采用open、readlines函数来实现,亦或者可以采用pandas库中的pd.read_csv来实现(若数据集为csv文件)

    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)

ps:filename是自己的数据集路径

1.2从文本文件中解析数据

首先我们需要从txt文本中,将数据进行导入和分割,因为该文本中的数据是分为两列属性。我们可以采用img,classLabelVector来分别存储。

def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)
    classLabelVector = []#用于存放标签
    img = []#用于存放图片
    index = 0
    for line in arrayOLines:
        line = line.strip() 
        listFromLine = line.split('\t')#将数据集每一行都分割来 分割后为'cats/cat.4987.jpg 0'
        for item in listFromLine:
            img_path, classLabel = item.split(' ')
            img_data = image_to_feature_matrix(img_path)
            img.append(img_data)
            classLabelVector.append(int(classLabel))
            index += 1
    return classLabelVector, img

(1)代码思路:我们首先通过Open函数打开存放有我们数据和标签的文件,通过readlines遍历文本当中的每一行。img,classLabelVector分别用来存放图片数据和标签。此后通过一次for循环,将文本数据中的每一行通过换行符进行分割,而后分割后的每一行数据在进行for循环,通过空格符进行分割,并通过append函数,存储在相对应的数组中。

如果你想要实现图像识别分类,你需要将图片信息转化为灰度图,而后将灰度图转换为特征向量来进行存储,否则很容易会造成输入的规模与分类器的规模不一致的问题。(因为我下载的数据集txt文本中图片不是完整路径,因此这里采用了拼接路径)

def image_to_feature_matrix(image_path, size=(64, 64)):
    # 读取图片文件
    img = cv2.imread('C:\\AI\\Lib\\cats_dogs_dataset\\'+image_path)
    
    # 缩放图片
    img = cv2.resize(img, size)
    
    # 将图片转换为灰度图
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 将灰度图转换为特征向量
    feature_vector = gray_img.flatten()
    
    return feature_vector

2.实例:使用K-近邻算法实现猫狗分类

2.1准备数据:从文本文件中解析数据

我们通过for循环和split分割属性,将其分别加入到对应的数组中,我们需要对图像进行处理(为了保证输入规模与KNN分类器的规模一致)。我们需要将图片转化为灰度图,并将其转化为特征向量存储。

def image_to_feature_matrix(image_path, size=(64, 64)):
    # 读取图片文件
    img = cv2.imread('C:\\AI\\Lib\\cats_dogs_dataset\\'+image_path)
    
    # 缩放图片
    img = cv2.resize(img, size)
    
    # 将图片转换为灰度图
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 将灰度图转换为特征向量
    feature_vector = gray_img.flatten()
    
    return feature_vector

def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numberOfLines = len(arrayOLines)
    classLabelVector = []#用于存放标签
    img = []#用于存放图片
    index = 0
    for line in arrayOLines:
        line = line.strip() 
        listFromLine = line.split('\t')#将数据集每一行都分割来 分割后为'cats/cat.4987.jpg 0'
        for item in listFromLine:
            img_path, classLabel = item.split(' ')
            img_data = image_to_feature_matrix(img_path)
            img.append(img_data)
            classLabelVector.append(int(classLabel))
            index += 1
    return classLabelVector, img

而后,我们采用KNN算法,定义一个classify函数,其中inX为输入的向量,X_train为训练集,labels为标签,k为选定的值。我们可以通过采用欧式距离公式来进行计算,而后通过最近距离的k个点频率最高的类别来确定输入数据的标签。

def classify(inX, X_train, labels, k):#knn算法
    dataSetSize = len(X_train)
    diffMat = np.tile(inX, (dataSetSize, 1)) - X_train
    sqDiffMat = diffMat**2
    sqDistance = sqDiffMat.sum(axis=1)
    distances = sqDistance**0.5
    sortedDisIndicies = distances.argsort()
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDisIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
    sortedClassCount = sorted(classCount.items(), key=lambda x: x[1], reverse=True) 
    return sortedClassCount[0][0]

而后我们可以通过train_test_split函数来划分训练集和测试集,在该示例中,我们将测试集设置为百分之二十。然后将img,classLabelVector分别作为训练集和测试集的参数传入。

if __name__ == "__main__":
    filename = 'C:\\AI\\Lib\\cats_dogs_dataset\\test.txt'
    classLabelVector, img = file2matrix(filename)
    print(img)
    print(classLabelVector)
    # 划分训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(img, classLabelVector, test_size=0.2, random_state=42)

进一步地,我们可以通过KNeighborsClassifier函数创建KNN分类器,也可以自主设置img_path,并通过我们定义的classify函数来实现knn算法及预测。

    # 创建KNN分类器
    knn = KNeighborsClassifier(n_neighbors=3)
    #通过输入预测
    img_path = 'cats/cat.4358.jpg'
    inX = image_to_feature_matrix(img_path)
    knn1 = classify(inX, X_train, y_train, k=3)
    print(knn1)

接下来就是训练模型以及计算该模型的准确率。我们可以通过fit、predict、accuracy_score函数来实现该功能。

    # 训练模型
    knn.fit(X_train, y_train)

    # 预测
    y_pred = knn.predict(X_test)

    # 计算准确率
    accuracy = accuracy_score(y_test, y_pred)
    print("准确率:", accuracy)

2.2分析数据:使用Matplotlib创建散点图

创建散点图之前,我们需要导入plt库(用来制图)。我们可以利用plt库当中的xlabel、ylabel来设置横纵坐标,scatter则可以用来绘制点的分散,我们可以设置点的颜色,以及某个颜色所代表的意义。最后我们通过show函数来展示散点图的分布。

    #散点图分布
    plt.scatter(range(len(y_pred)), y_pred, c='r', label='Predicted')
    plt.scatter(range(len(y_test)), y_test, c='b', label='True')
    plt.xlabel('Index')
    plt.ylabel('Class')
    plt.legend()
    plt.show()

2.3效果图展示

该结果展示的是特征矩阵,因为该示例的数据集为猫狗图片,因此特征矩阵存放的是像素的值。

该结果展示的是各图片所对应的标签,其中0表示猫,1表示狗。

该图片展示的是散点图的分布,因为该示例为二分类任务。从该图上看来,该模型的性能还是较好的。

3.常见错误及解决思路

常见错误:(1)我们在对图像数据进行存储的时候,规模和分类器的规模会不一致。

                  (2)在进行数据分割的时候,很容易造成分割不完全,以至于后续无法找到正确路径

                  (3)找不到txt文件中的图片文件出现FileNotFound的Error

解决思路:(1)我们利用cv2进行图像的转化,将其像素的值存储到img数组中,当中可以利用flatten来将其拉伸为一维数组

                  (2)我们在分割的时候需要注意我们每一步代码,分割后的结果是什么,像该示例我们第一次按换行符进行分割,分割的结果是文本内的每一行数据。需要在进行一次分割,将图像数据与标签分别进行存储

                  (3)因为txt文件当中的图像数据并不是完整的路径,因此我们需要通过拼接路径,将完整的图片路径拼出来。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值