机器学习实验作业一----knn算法

机器学习课程的第一个算法knn算法,全称K-Nearest Neighbor,k最邻近算法,为机器学习中最常用,也是最简单的算法。KNN通过测量不同特征值之间的距离来进行分类。本文实现的是较为简单的knn算法,包括测试集,训练集,文本记录转化为Numpy的解析,使用matplotlib创建散点图,归一化数值。

本文的训练集,测试集是来源于网上查询的鸢尾花(iris)数据集。

knn算法概述:

knn算法是最简单的分类算法,主要用于将一个还未分类的点进行分类,得到该点的标签。

K近邻,就是K个最近的邻居的意思,说的是每个样本都可以用它最接近的K个邻近值来代表,也就是该点的标签是用他k个最近邻居中占比最大的标签(每个邻居都带有标签,统计标签出现的个数,取最多的那个标签),把该点分类到其中。

课本中的算法思路:

        对未知类别属性的数据集中的每个点依次执行以下操作:

  1.  计算已知类别数据集中点与当前点之间的距离。
  2. 按照距离递增次序排序。
  3. 选取与当前点距离最小的k个点。
  4. 确定前k个点所在类别出现的频率。
  5. 返回前k个点出现频率最高的类别作为当前点的预测分类。
实现过程需要用到的库:

Pandas 用于数据处理

NumPy 用于数值计算

Matplotlib 用于绘图

归一化处理: 

由于数据的样式不一定统一,当数据的两个数值之间的差距过大的时候,例如(1,1000)(2,3000)这两个数据,得到欧氏距离根号(1*1+2000*2000),我们可以很清楚的看到,由于x比y小很多,所以该数据的受y的影响比较大,这不是我们想看到的,因此我们采用归一化处理,也就是说我们要让所有特征的取值在0到1中分布,这样就可以使得特征影响的相同。

我这边采用的归一化公式为:

                        newvalue=(oldvalue-min)/(max-min)

max和min是数据集中的最小特征值和最大特征值。我们把所有的值都转化为0~1中的值。

当然,归一化公式并不唯一,具体情况具体分析了。

 训练集样式:

测试集样式:

 


编码运行问题及其我编写代码前不了解的函数:

  1. 读取训练集数据文件 train_data = pd.read_csv("训练集路径", sep='\s+'),函数默认情况下是用逗号分隔的,这边由于我的格式是以空格分隔的,所以加上sep='\s+'来表示是以空格区分的,当然如果你的格式是以回车分隔的,也可以改为sep='\t'。
  2. plt.figure()创建一个新的图形窗口或画布。 
  3. plt.scatter(横坐标, 纵坐标, color=颜色, label=标签)用来绘制图上的一个点。
  4. 由于我未正确设置中文字体,matplotlib 画出的散点图无法显示中文,并且会抛出错误。因此我使用以下代码来表示我们采用的是微软雅黑字体,就可以正常显示中文。

    plt.rcParams['font.sans-serif'] = ['SimHei']

      5.X_train.max(axis=0)这里的X_train是变量名,axis=0表示沿着数组行的方向,axis=1就是表示沿着数组列的方向进行。max也就是是取这一行(列)的最大值。

       6.np.mean(a == b)这个函数的作用就是a与测试集标签b相等的比例。

 部分代码解释:

1.画出训练集散点图:

 创建画布,并利用训练集中的数据绘制散点图。for循环中每次取到训练集中的一个数据,plt.scatter()函数根据这个鸢尾花的长度为x,宽度为y来在散点图中绘制这个点。其中xlabel,ylabel,title分别表示x轴,y轴,还有散点图的名称。然后显示散点图。以下是该部分代码和得到的散点图。

plt.figure()//创建画布
colors = {'setosa': 'red', 'versicolor': 'blue', 'virginica': 'green'}
for i in range(len(train_data)):
    row = train_data.iloc[i]
    plt.scatter(row["Sepal.Length"], row["Sepal.Width"], color=colors[row["Species"]], label=row["Species"])
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.xlabel('鸢尾花长度')
plt.ylabel('鸢尾花宽度')
plt.title('训练集--鸢尾花长度与宽度的关系')
plt.show()

 

 2.欧式距离计算:

欧式距离也算是空间中两点间的直线距离,也就是传统的空间距离公式:

                        d=\sqrt{(x1-x2)^{2}+(y1-y2)^{2}+(z1-z2)^{2}}

那么对应函数也就是:

  1. (x1 - x2) 计算了两点在每个维度上的差值。
  2. (x1 - x2) ** 2 对每个维度上的差值进行平方。
  3. np.sum(...) 对所有维度上的平方差值求和。
  4. np.sqrt(...) 对上一步得到的和进行平方根运算,得到最终的欧式距离。
def euclidean_distance(x1, x2):
    return np.sqrt(np.sum((x1 - x2) ** 2))

 3.归一化:

在代码中我们用max_vals来存储x这个特征值中的最大值,x_train.max(axis=0)(这里的axis是变量名,可以自己取)表示的是在这个训练集中x_train这一列的最大值。后面的x_train_scaled也就是把数据归一化结论得到的训练集表示。

max_vals = X_train.max(axis=0)
min_vals = X_train.min(axis=0)
X_train_scaled = (X_train - min_vals) / (max_vals - min_vals)

4. K 近邻分类器:(也就是上面说的课本中的算法思路)

对于每个测试集中的点,求出该点与训练集中每个点的距离存储在distances中。np.argsort(distances)[:k]是用二分排序得到距离该点的最近k个存在nearest_indices中

在把那k个点的标签都加入到 nearest_laels中,得到最大标签数的那个加入测试集标签中。

def predict_knn(X_train, y_train, X_test, k):
    y_pred = []
    for test_point in X_test:
        distances = [euclidean_distance(test_point, train_point) for train_point in X_train]
        nearest_indices = np.argsort(distances)[:k]
        nearest_labels = [y_train[i] for i in nearest_indices]
        pred_label = max(set(nearest_labels), key=nearest_labels.count)
        y_pred.append(pred_label)
    return y_pred

5.得到最合适的k值

遍历k的取值,我这边k的取值为2~20。

将每一个k的值用临近分类器分类,然后用np.mean()计算准确率。

用best_k, best_accuracy,y_pred_test_best来记录准确率最高的k,和最高的准确率,还有这个最高的k对应的测试集中各个点的分类标签。

for j in range(2, 21):
    y_pred_test_custom = predict_knn(X_train_scaled, y_train, X_test_scaled, j)
    accuracy = np.mean(y_pred_test_custom == y_test)
    accuracies.append(round(accuracy, 3))
    print(f"准确率k={j}: {accuracy:.3f}")
    if best_accuracy < accuracy:
        best_k = j
        best_accuracy = accuracy
        y_pred_test_best = y_pred_test_custom
print(f"k取值为{best_k}的准确率最高,准确率为{best_accuracy:.3f} ")

 

 6.计算准确率,精确值,召回率,f1值

按照课本上给出的定义和公式:

TP 表示真正例,TN 表示真负例,FP 表示假正例,FN 表示假负例

  1. 准确率: 准确率是分类器正确预测的样本数占总样本数的比例。 公式:准确率 = (TP + TN) / (TP + TN + FP + FN)

  2. 精确率: 精确率衡量的是被分类器预测为正类的样本中有多少是真正的正类样本。 公式:精确率 = TP / (TP + FP)

  3. 召回率: 召回率衡量的是真正的正类样本中有多少被分类器预测为正类。 公式:召回率 = TP / (TP + FN)

  4. F1 值: F1 值是精确率和召回率的调和平均值,综合考虑了精确率和召回率。 公式:F1 值 = 2 * (精确率 * 召回率) / (精确率 + 召回率)

def calculate(y_test, y_pred_test_best):
    accuracy = best_accuracy
    precision = precision_score(y_test, y_pred_test_best, average='weighted')
    recall = recall_score(y_test, y_pred_test_best, average='weighted')
    f1=(accuracy*recall)*2/(accuracy+recall)

    print("准确率: {:.2f}".format(accuracy))
    print("精确率: {:.2f}".format(precision))
    print("召回率: {:.2f}".format(recall))
    print("F1值: {:.2f}".format(f1))

calculate(y_test, y_pred_test_best)

学习别人的代码之后才发现对于这四个值都有对应的计算函数,例如accuracy_score, precision_score, recall_score, f1_score这些都在sklearn.metrics库中。

并且classification_report(y_test, y_pred_test_best)这个代码可以直接生成如图的表格,确实功能强大。

 

 代码展示:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import classification_report

train_data = pd.read_csv("C:\\Users\\李烨\\Desktop\\新建文件夹\\6\\iris.txt", sep='\s+')

X_train = train_data[["Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"]].values
y_train = train_data["Species"].values

plt.figure()
colors = {'setosa': 'red', 'versicolor': 'blue', 'virginica': 'green'}
for i in range(len(train_data)):
    row = train_data.iloc[i]
    plt.scatter(row["Sepal.Length"], row["Sepal.Width"], color=colors[row["Species"]], label=row["Species"])

plt.rcParams['font.sans-serif'] = ['SimHei']
# plt.rcParams['axes.unicode_minus'] = False
plt.xlabel('鸢尾花长度')
plt.ylabel('鸢尾花宽度')
plt.title('训练集--鸢尾花长度与宽度的关系')
plt.show()

max_vals = X_train.max(axis=0)
min_vals = X_train.min(axis=0)
X_train_scaled = (X_train - min_vals) / (max_vals - min_vals)


def predict_knn(X_train, y_train, X_test, k):
    y_pred = []
    for test_point in X_test:
        distances = [euclidean_distance(test_point, train_point) for train_point in X_train]
        nearest_indices = np.argsort(distances)[:k]
        nearest_labels = [y_train[i] for i in nearest_indices]
        pred_label = max(set(nearest_labels), key=nearest_labels.count)
        y_pred.append(pred_label)
    return y_pred

def euclidean_distance(x1, x2):
    return np.sqrt(np.sum((x1 - x2) ** 2))


test_data = pd.read_csv("C:\\Users\\李烨\\Desktop\\新建文件夹\\6\\iris.csv")

X_test = test_data[["Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"]].values
y_test = test_data["Species"].values

X_test_scaled = (X_test - min_vals) / (max_vals - min_vals)

accuracies = []

best_k = 2
best_accuracy = 0
for j in range(2, 21):
    y_pred_test_custom = predict_knn(X_train_scaled, y_train, X_test_scaled, j)

    accuracy = np.mean(y_pred_test_custom == y_test)
    accuracies.append(round(accuracy, 3))
    print(f"准确率k={j}: {accuracy:.3f}")
    if best_accuracy < accuracy:
        best_k = j
        best_accuracy = accuracy
        y_pred_test_best = y_pred_test_custom
print(f"k取值为{best_k}的准确率最高,准确率为{best_accuracy:.3f} ")
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score


def calculate(y_test, y_pred_test_best):
    accuracy = best_accuracy
    precision = precision_score(y_test, y_pred_test_best, average='weighted')
    recall = recall_score(y_test, y_pred_test_best, average='weighted')
    f1=(accuracy*recall)*2/(accuracy+recall)

    print("准确率: {:.2f}".format(accuracy))
    print("精确率: {:.2f}".format(precision))
    print("召回率: {:.2f}".format(recall))
    print("F1值: {:.2f}".format(f1))

calculate(y_test, y_pred_test_best)

print(classification_report(y_test, y_pred_test_best))

代码运行结果展示:

 

优缺点分析(参照课本): 

优点:

  1. 简单易理解:KNN 是一种直观且易于理解的算法,适合入门级别的学习和实践。

  2. 适用于多分类问题:KNN 可以处理多分类问题,并且对特征空间的结构没有严格的假设。

  3. 对异常值不敏感:KNN 算法对异常值不敏感,因为它是基于邻居间的距离计算结果。

缺点:

  1. 计算复杂度高:在预测阶段,KNN 需要计算新数据点与所有训练集数据点的距离。

  2. 预测速度较慢:由于需要计算新数据点与所有训练数据点的距离,导致在预测阶段速度较慢。

  3. 对数据不平衡和高维数据敏感:当数据集存在类别不平衡或者维度较高时,KNN 的表现可能会受到影响。

  4. 参数选择困难:KNN 中的 K 值选择对算法的性能影响较大,选择不当可能导致过拟合或欠拟合。


 

                        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/490903.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pytorch中关于BF16、FP16的一些操作

文章目录 前提创建BF16和FP16的数据BF16和FP16的二进制存储格式如何根据十进制数得到对应的二进制存储如何根据二进制存储计算对应的十进制数&#xff1f;第一种方法第二种方法 二进制乘法如果是负数怎么办&#xff1f;如何手动计算BF16对应的的二进制存储格式参考链接 前提 好…

湖北汽车工业学院 实验一 关系数据库标准语言SQL

头歌 实验一 关系数据库标准语言SQL 制作不易&#xff01;点个关注呗&#xff01;为大家创造更多的价值&#xff01; 目录 头歌 实验一 关系数据库标准语言SQL**制作不易&#xff01;点个关注呗&#xff01;为大家创造更多的价值&#xff01;** 第一关&#xff1a;创建数据库第…

Chrome/Edge 使用 Markdown Viewer 查看 Markdown 格式文件

Chrome/Edge 使用 Markdown Viewer 查看 Markdown 格式文件 0. 引言1. 安装 Markdown Viewer 插件2. 使用 Markdown Viewer 阅读 Markdown 格式文件 0. 引言 大部分程序员都喜欢 Markdown 格式的文件&#xff0c;这时给一些没有在电脑上安装 Markdown 编辑器的同事分享资料时&…

脏牛提权(靶机复现)

目录 一、脏牛漏洞概述 二、漏洞复现 1.nmap信息收集 1.1.查看当前IP地址 1.2.扫描当前网段&#xff0c;找出目标机器 1.3.快速扫描目标机全端口 三、访问收集到的资产 192.168.40.134:80 192.168.40.134:1898 四、msf攻击 1.查找对应exp 2.选择对应exp并配置相关设…

基于nodejs+vue健美操评分系统python-flask-django-php

本系统采用的数据库是MySQL&#xff0c;使用nodejs技术开发。在设计过程中&#xff0c;很好地发挥了该开发方式的优势&#xff0c;让实现代码有了良好的可读性&#xff0c;而且使代码的更新和维护更加的方便&#xff0c;操作方便&#xff0c;对以后的维护减少了很多麻烦。系统的…

wpf程序调用macad的c++编写的dll

1.把macad里的build&#xff0c;source文件夹复制到一个文件夹里 2.创建一个wpf项目&#xff0c;在解决方案里添加macad.occt项目 3.把macad.occt设为dll文件&#xff0c;修改平台工具集&#xff0c;在macadtest里引用macad.occt 4.运行&#xff0c;应该会报错&#xff0c;说找…

「09」媒体源:播放本地或在线的音视频GIF文件

「09」媒体源播放本地或在线的音视频GIF文件 通过媒体源功能&#xff0c;您可以添加自己想要展示的各种视频内容&#xff0c;例如自己的视频课程、电影或客户见证视频、以及GIF动画等。 &#xff08;图层叠加效果&#xff09; &#xff08;绿幕抠像叠加效果&#xff09; 缺点…

Covalent Network(CQT)的以太坊时光机:在 Rollup 时代确保长期数据可用性

以太坊正在经历一场向 “Rollup 时代” 的转型之旅&#xff0c;这一转型由以太坊改进提案 EIP-4844 推动。这标志着区块链技术的一个关键转折&#xff0c;采用了一种被称为“数据块&#xff08;blobs&#xff09;”的新型数据结构。为了与以太坊的扩容努力保持一致&#xff0c;…

解析汽车充电桩主板的常见故障表现、原因及应对方法

充电桩主板作为充电桩的核心组件&#xff0c;直接影响着充电桩运行的安全性与稳定性。然而&#xff0c;在使用过程中&#xff0c;充电桩主板难免会因各种原因而出现一些故障情况&#xff0c;因此&#xff0c;了解这些原因并采取相应的应对方法对维护充电桩的正常运行起着至关重…

c语言应该怎么系统的学习?

c语言应该怎么系统的学习? 系统性学习C语言&#xff0c;这个描述首先是给人目标不明确&#xff0c;概念不清晰的映像。在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c语言的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后…

centos7 安装influxdb+telegraf+grafana 监控服务器

influxdb influxdb是一个时间序列数据库, 所有数据记录都会打上时间戳, 适合存储数字类型的内容 telegraf telegraf 可以用于收集系统和服务的统计数据并发送到influxdb grafana grafana 是一个界面非常漂亮, 可直接读取influxdb数据展示成各种图表的开源可视化web软件 安…

探索 JDK 11 的新特性:迈向 Java 平台的下一个里程碑

随着时间的推移&#xff0c;Java 平台一直在不断演进和改进&#xff0c;为开发人员提供更好的工具和功能。JDK 11 是 Java 平台的一个重要版本&#xff0c;引入了许多新的特性和改进&#xff0c;为开发人员带来了全新的体验和可能性。本文将介绍 JDK 11 中一些重要的新特性&…

python基础语法--快速入门

目录 一、字面量1.1定义 二、关键字三、注释四、引号五、输入输出六、缩进七、数据类型转换八、标识符九、运算符 一、字面量 1.1定义 字面量&#xff1a;在代码中&#xff0c;被写下来的固定的值。 python中哪些值可以被写下来&#xff0c;如何在代码中写他们呢&#xff1f;…

JavaWeb开发-前端HTML基础

1.HTML的基本语法 HTML是什么&#xff1f;&#xff1a;HTML是一种超文本标记语言&#xff0c;负责网页的结构&#xff0c;设计页面的元素内容等 超文本&#xff1a;超越文本限制&#xff0c;除了文本信息&#xff0c;还可以定义图片&#xff0c;音频&#xff0c;视频等标记语言…

2024 年广西职业院校技能大赛高职组《云计算应用》赛项赛题第 5 套

#需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; #需要资源或有问题的&#xff0c;可私博主&#xff01;&#xff01;&#xff01; 某企业根据自身业务需求&…

中科数安 || 公司办公文件资料加密、防泄密管理软件系统

#文件防泄密软件# 中科数安提供专业的公司文件资料加密与防泄密管理系统&#xff0c;这套软件主要服务于企业用户&#xff0c;以强化内部信息安全、防止重要数据泄露为核心目标。 中科数安 | 电脑文件防泄密软件 PC地址&#xff1a; www.weaem.com 该系统具备以下功能特性&a…

如何解决kafka rebalance导致的暂时性不能消费数据问题

文章目录 背景思考答案排它故障转移共享 背景 之前在review同组其它业务的时候&#xff0c;发现竟然把kafka去掉了&#xff0c;问了下原因&#xff0c;有一个单独的服务&#xff0c;我们可以把它称为agent&#xff0c;就是这个服务是动态扩缩容的&#xff0c;会采集一些指标&a…

格瑞纳电子邀您参观2024杭州快递物流展

2024长三角快递物流供应链与技术装备展览会 2024.7.8-10 杭州国际博览中心 参展企业介绍 北京格瑞纳电子产品有限公司是一家立足于专业科学技术领域集产品代理、培训咨询和个性化增值服务的高科技公司&#xff0c;于2009年成立于北京&#xff0c;立足于复杂系统仿真领域&…

水电站泄洪预警广播系统方案

一、行业背景 近年来由于危险河道管理措施不到位&#xff0c;调峰电站泄水风险长期存在&#xff0c;信息通报制度缺失以及民众安全警觉性不高等因素导致的水电站在泄洪时冲走下游河道游客以及人民财产的事故频发。 我司通过物联网、云计算、大数据、人工智能等技术手段&#x…

随机链表的深拷贝

目录 一、何为深拷贝&#xff1f; 二、题目 三、思路 1.拷贝节点插入到原节点后面 2.控制拷贝节点的random 3.脱离原链表 : 尾插的思想 四、代码 五、附加 一、何为深拷贝&#xff1f; 一个引用对象一般来说由两个部分组成&#xff1a;一个具名的Handle&#xff0c;也就…