机器学习————KNN算法

一、KNN算法介绍

1.1 KNN算法概述

KNN(K-Nearest Neighbor)算法是机器学习算法中最基础、最简单的算法之一,是一种分类回归的统计方法,是监督学习。KNN通过测量不同特征值之间的距离来进行分类。所谓k近邻,就是k个最近的邻居的意思,说的是每个样本类别都可以用它最接近的k个邻居的类别来代表。 就比如:判断一个人的人品好坏,只需要观察与他来往最密切的几个人的人品好坏就可以得出,即“近朱者赤,近墨者黑"。

举个例子:

图中绿色的点是我们要预测的那个点,假设K=3。那么KNN算法就会找到与它距离最近的三个点,看看哪种类别多一些,例子中蓝色三角形有两个,红色圆有一个,那么新来的绿色点就归类到蓝三角了。

1.2 KNN算法的一般流程

1、收集数据:可以使用任何方法。
2、准备数据:距离计算所需要的数值,最好是结构化的数据格式。
3、分析数据:可以使用任何方法。
4、测试算法:计算错误率。
5、使用算法
    5.1. 计算预测数据与训练数据之间的距离
    5.2. 将距离进行递增排序
    5.3. 选择距离最小的前K个数据
    5.4. 确定前K个数据的类别,及其出现频率
    5.5. 返回前K个数据中频率最高的类别(预测结果)

1.3 KNN算法的距离计算

KNN算法中对于距离的计算有好几种度量方式,比如欧式距离、曼哈顿距离、切比雪夫距离等等,最常用的就是欧式距离。

欧式距离计算公式

\sqrt{\sum_{i=1}^{n}\left ( x_{i}-y_{i} \right )^{2}}

1.4 KNN算法的K值选择

K值的大小对算法的影响:

K值太大,会导致预测标签比较稳定,可能过平滑,容易欠拟合

K值太小,会导致预测的标签比较容易受到样本的影响,容易过拟合

所以对于K值的选取,我们通常使用交叉验证来验证,交叉验证:将样本数据按照一定比例,拆分出训练用的数据和验证用的数据,比如6:4拆分出部分训练数据和验证数据,从选取一个较小的K值开始,不断增加K的值,然后计算验证集合的方差,最终找到一个比较合适的K值。

二、实现KNN算法完成鸢尾花分类

2.1数据集介绍

鸢尾花数据集共收集了三类鸢尾花,即Setosa鸢尾花、Versicolour鸢尾花和Virginica鸢尾花,包括4个属性,分别为花萼的长、花萼的宽、花瓣的长和花瓣的宽。每个类别50个样本。

2.2代码介绍

2.2.1初始化数据集和数据集划分

读取数据集文件中的数据到列表中,因为数据集中单个数据特征是以,分隔开,所以按,分隔为一个样本数据再存到数组data_temp

# 初始化数据集
def init(adder):
    f = open(adder)  # 打开数据文件文件
    lines = f.readlines()  # 把全部数据文件读到一个列表lines中
    data_test = []
    for line in lines:  # 把lines中的数据逐行读取出来
        data_test.append(line.rstrip('\n').split(','))
    data_temp = np.array(data_test)
    return data_temp

使用numpy库把数据打乱,再按照指定比例把数据划分为数据集验证集,用在确定模型准确率的时候使用

# 将数据随机分为训练集和测试集
def split_data(data, train_ratio):
    np.random.shuffle(data)#打乱数据
    train_size = int(len(data) * train_ratio)
    train_data = data[:train_size]#按照比例划分
    test_data = data[train_size:]
    return train_data, test_data

2.2.2计算待测样本和数据集距离,并从距离最近的K个数据中来预测数据类别

通过数据特征来计算待测样本和数据集中每个数据的欧氏距离并存储,然后从存储的数据数组中按距离排序,再从最近的K个数据中找出出现次数最多的数据类别作为预测结果返回。

# 计算两个样本之间的距离
def distance_out(need_judge, source):
    #类型转化
    source = source.astype(float)
    x = need_judge[0] - source[0]
    y = need_judge[1] - source[1]
    z = need_judge[2] - source[2]
    r = need_judge[3] - source[3]
    #计算欧氏距离
    distance = math.sqrt((x ** 2 + y ** 2 + z ** 2 + r ** 2))
    return distance
# 计算待测样本与训练样本的距离
def argue(need_judge, data_temp):
    # 获取训练样本数量
    times = data_temp.shape[0]
    # 初始化一个数组来存储距离和类别信息
    distance_all = np.zeros((1, 2))
    for time in range(times):
        #遍历样本,计算距离并存储距离和样本的类别
        temp = data_temp[time]
        temp_temp = temp[0:4]
        distance_temp = distance_out(need_judge, temp_temp)
        new_row = np.array((distance_temp, temp[4]), dtype=str)
        new_row = np.array(new_row).reshape((1, 2))
        #把包含距离和数据类别信息的新数组作为新的一行添加到distance_all中
        distance_all = np.r_[distance_all, new_row]
    return distance_all
# 根据K近邻算法找到合适的类别
def find_suitable(distance_all, K):
    # 从距离数组中去除第一行(因为它是零行)
    new_distance_all = distance_all[1:]
    # 按距离对样本进行排序并获取索引
    sorted_indices = np.argsort(new_distance_all[:, 0])
    # 获取前K个最近的样本
    min_k_rows = new_distance_all[sorted_indices[:K], :]
    # 获取这些样本的类别
    min_name = min_k_rows[:, 1]
    # 统计类别出现的次数
    counts = Counter(min_name.tolist())
    # 找到出现次数最多的类别
    most_common_str = max(counts, key=counts.get)
    # 返回出现次数最多的类别
    return most_common_str

2.2.3预测结果和使用验证集计算准确率

通过计算待测样本和数据样本之间的距离并找到最合适的类别,以及把数据集划分为训练集验证集来计算准确率

# 预测结果
def train(need_judge, K, data):
    # 计算待测样本与训练样本的距离并找到最合适的类别
    distance_all = argue(need_judge, data)
    kinds = find_suitable(distance_all, K)
    return kinds

# 从样本数据中获取特征值
def get_point(data):
    #print("Data:", data)
    #print("Data size:", len(data))
    return data[0], data[1], data[2], data[3]

# 计算模型的准确率
def ua(K, train_ratio):
    # 初始化数据集
    data = init(data_address)
    # 划分训练集和测试集
    train_data, test_data = split_data(data, train_ratio)
    # 获取测试集的数量
    data_number = test_data.shape[0]
    right = 0
    faid = 0
    count = 0
    # 对每个测试样本进行预测
    for temp in test_data:
        count += 1
        print("正在进行第", count, "次验证")
        # 获取特征值
        x, y, z, r = get_point(temp)
        need_judge = np.array([x, y, z, r], dtype=float)
        # 预测样本类别
        judge = train(need_judge, K, train_data)
        # 统计预测正确和错误的样本数量
        if judge == temp[4]:
            right += 1
        else:
            faid += 1
    # 计算准确率
    right_faid = (float)((right) / (test_data.shape[0]))
    print("当前模型的成功率是百分之", right_faid * 100)

2.2.4交互界面

写了一点简单交互,让用户选择是进行预测还是进行计算准确率以及是否退出,在进行预测和准确率计算时都有让用户输入K值,并且在计算准确率时还有让用户指定训练集和验证集的比例。

if __name__ == '__main__':
    while True:
        choose = input("1.查看准确率\n"
                       "2.开始预测\n"
                       "3.退出\n")

        if choose == '1':
            K = int(input("输入K: "))
            train_ratio = float(input("输入训练集比例(例如0.8表示80%): "))
            ua(K, train_ratio)
        elif choose == '2':
            K = int(input("输入K: "))
            x = float(input("输入特征值1: "))
            y = float(input("输入特征值2: "))
            z = float(input("输入特征值3: "))
            r = float(input("输入特征值4: "))
            need_judge = np.array([x, y, z, r], dtype=float)
            data = init(data_address)
            kinds = train(need_judge, K, data)
            print("根据您输入的预测值,模型猜测结果是", kinds)
        elif choose == '3':
            break
        else:
            print("输入错误")
    print("欢迎下次使用")

2.2.5遇到的问题

在写train函数时,考虑的是在预测时的使用,所以一开始写的下面这个样子

# 预测结果
def train(need_judge, K):
    # 初始化数据集
    data = init(data_address)
    # 计算待测样本与训练样本的距离并找到最合适的类别
    distance_all = argue(need_judge, data)
    kinds = find_suitable(distance_all, K)
    return kinds

导致在计算准确率中的验证时会有冲突,所以最后使用这个版本,而在预测时选择重新初始化一次数据来传参。

# 预测结果
def train(need_judge, K, data):
    # 计算待测样本与训练样本的距离并找到最合适的类别
    distance_all = argue(need_judge, data)
    kinds = find_suitable(distance_all, K)
    return kinds

2.3结果截图展示

查看准确率

预测

三、总结

3.1KNN算法的优点

1. 简单易实现:KNN算法的原理简单,易于理解和实现,无需训练过程

2.适用于多分类问题:KNN算法可以应用于多分类问题,并且对样本分布的假设较少。

3.对异常值不敏感:KNN算法对异常值不敏感,因为它是通过距离计算来确定最近邻样本,即使某个样本是异常值,也不会对整体结果产生很大影响

3.2KNN算法的缺点

1.计算复杂度高:KNN算法需要计算测试样本与所有训练样本之间的距离,计算复杂度较高,尤其是在大规模数据集上。

2.高度数据相关:KNN算法依赖于特征空间中的距离度量,如果特征空间中的距离度量不合理或者特征权重不准确,可能会导致预测性能下降。

3.决策边界不规则:KNN算法的决策边界通常是不规则的,因为它只考虑了局部样本的信息,而没有对全局进行建模。
4.对内存要求较高,因为该算法存储了所有训练数据。
5.预测阶段可能很慢:如果数据样本过多的话,需要全部遍历就会耗时间。

3.3思考

3.3.1KNN算法是否可以用于DNA检测等任务中

应该是可以。但是效率应该会很低,因为大多数的DNA序列数据巨大,数据特征的高维度再加上组合的多样性会导致计算效率很低,从而导致预测效率很低。

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值