机器学习笔记(四)——聚类算法KNN、Kmeans、Dbscan

写在前面:

写本系列**(自用)**的目的是回顾已经学过的知识、记录新学习的知识或是记录心得理解,方便自己以后快速复习,减少遗忘。概念部分大部分来自于机器学习菜鸟教程,公式部分也会参考机器学习书籍、阿里云天池。机器学习如果只啃概念始终学不牢,因此我打算概念与代码结合。

Part 2 机器学习算法

五、KNN

1、KNN的基本原理

KNN,也叫K近邻算法,是一种简单且常用的分类和回归算法。它是监督学习的一种,核心思想是通过计算待分类样本与训练集中各个样本的距离,找到距离最近的 K 个样本,然后根据这 K 个样本的类别或值来预测待分类样本的类别或值。

现在举一个例子,示例中的图片来自b站up小萌Annie的K近邻算法视频:

假设有两种狼群,狼群A和狼群B。其中,狼群A的脚印用图中绿色的圆圈来表示,狼群B的脚印用图中绿色的正方形来表示。现在给出一个不知道类别的脚印(图中黑色爪印),问这个脚印是狼群A留下的还是狼群B留下的。解决这个问题可以使用KNN算法。

假设我们设置KNN的距离超参数k = 1。也就是说,以待分类样本(黑色爪印)为圆心,k=1为半径画圆,看圆内哪种脚印数量多。例如图中,当k = 1时,圆圈的数量为1,方形的数量为0,因此我们判断黑色脚印是圆形,即待分类样本属于狼群A。

同理,k = 3时,圆圈的数量为2,方形的数量为1,因此我们判断黑色脚印是圆形,即待分类样本属于狼群A。

k = 5时,圆圈的数量为2,方形的数量为3,因此我们判断黑色脚印是方形,即待分类样本属于狼群B。

这就是KNN算法解决分类问题的案例(解决回归问题就是取k个最近邻点的平均值)。那么需要解决的问题就是KNN算法的距离如何度量。

2、距离度量(可以只了解欧氏距离)

这里shun'dai常用的距离度量方法如下:

(1)欧式距离

欧式距离是KNN最常用的距离度量,计算n维空间中两点x、y的直线距离的公式为:

(2)曼哈顿距离

计算n维空间中两点在网格状空间中的最短路径距离,如城市街区距离:

(3)切比雪夫距离

表示两点在各维度上差值的最大值:

(4)闵可夫斯基距离

是欧氏距离和曼哈顿距离的广义形式:

当p=1时为曼哈顿距离,p=2时是欧式距离,p趋于无穷时等价于切比雪夫距离。

(5)余弦相似度

衡量两个n维向量方向的相似性:

这里,分子是两个向量x、y的点积;分母是向量模长的乘积。

(6)汉明距离

两个等长字符串对应位置不同字符的数量,常用于分类变量:

d(x, y) = 不同位置的数量

(7)马氏距离

考虑数据分布协方差的距离度量,消除特征间的相关性:

其中,S是数据的协方差矩阵。

(8)编辑距离

将一个字符串转换为另一个字符串所需的最少编辑操作次数(插入、删除、替换)。

在KNN中,距离度量的选择直接影响算法性能。不同距离函数会导致不同的近邻定义,从而影响结果,最常用的距离是欧氏距离。

例如,图像识别,地理坐标分析等常用欧氏距离;文本分类等常用余弦相似度;棋盘游戏可以考虑切比雪夫距离。如果难以抉择如何选取距离,可以通过交叉验证比较不同距离函数的性能。

3、KNN步骤总结

KNN算法的步骤可以概括如下:

1、计算距离:计算待分类样本与训练集中每个样本的距离。

2、选择k个最近邻样本。

3、投票或取平均:对于分类问题 ,K 个最近邻中出现次数最多的类别即为待分类样本的类别;对于回归问题,K 个最近邻的值的平均值即为待分类样本的值。

4、KNN的代码实现

python 复制代码
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score

# 加载Iris数据集
iris = datasets.load_iris()
X = iris.data # 只取前两个特征
y = iris.target

# 将数据集拆分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 创建KNN模型,设置K值为3
knn = KNeighborsClassifier(n_neighbors=3)
'''
这里是默认使用欧氏距离,也就是:
knn = KNeighborsClassifier(n_neighbors=3, metric='euclidean')
metric就是选择距离度量方式,'euclidean'是欧式距离
'manhattan'是曼哈顿、'chebyshev'是切比雪夫、'cosine'是余弦、'hamming'是汉明、'mahalanobis'是马氏距离
metric='minkowski', p=2这样是参数为2的闵可夫斯基距离
当然,也可以自定义距离函数
写好函数后将函数传入,即 metric= 函数名 即可。
'''

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

# 在测试集上进行预测
y_pred = knn.predict(X_test)

# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"KNN模型的准确率: {accuracy:.4f}")

六、k-means

1、k-means的原理

k-means算法也是一种经典的无监督学习算法。它的目标是:将n个数据点划分为k个簇,每个簇由其质心代表,使得所有数据点到其所属质心的平方和距离最小。

2、算法步骤

1、初始化:随机选取k个数据点作为初始的质心;

2、分配:将每个数据点分配到距离最近的质心所在的簇;(这里默认使用且最常使用的是欧式距离,也可以使用其他距离度量方式)

3、更新:重新计算每个簇的质心,质心的计算是对簇内所有数据点的每个维度取平均值。

例如某簇里有三个点:(1, 2),(3, 4),(5, 6),该簇的中心就是(3, 4)。=>((1+3+5)/3,(2+4+6)/3)

4、迭代:重复步骤 2-3,直到质心不再变化或达到最大迭代次数。

3、示例

示例来源于b站up平安喜悦孙瑜的k-means聚类算法讲解视频。

1、初始化三个质心:黄、蓝、绿

2、对每个白色的点,分别计算它到这三个质心的距离。离哪个质心近,就把它归为那一类。每个点均分类完成后如下图:

3、计算出三个类的质心,作为新的簇中心:

4、算出簇中心后,重新计算每个点离三个质心的距离,重新分类;一直循环直到质心不再变化或者达到最大迭代次数。

4、代码实现

python 复制代码
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt

# 生成模拟数据(3个簇)
X, _ = make_blobs(n_samples=300, centers=3, cluster_std=0.60, random_state=42)

# 构建 K-means 模型
kmeans = KMeans(n_clusters=3, init='k-means++', max_iter=300, random_state=42)
y_pred = kmeans.fit_predict(X)

# 可视化结果
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='viridis')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=300, c='red', marker='X')
plt.title('K-means Clustering')
plt.show()

七、DBSCAN

1、算法原理

DBSCAN是一种基于密度的空间聚类算法,能够将高密度区域划分为簇,并将低密度区域识别为噪声点。DBSCAN中有以下几个核心概念:

设有n个待聚类点,当前操作点设为p点。

1、ε 邻域:以点 p 为中心、半径为 ε 的区域。如下图所示,p点为中心, ε =2,黑色圆内即为ε 邻域。

2、MinPts:核心点最小点数,由用户指定。

3、核心点:若点 p 的 ε 邻域内至少包含 MinPts 个点,则 p 是核心点。如下图所示:设MinPts为4,此时p点的ε 邻域内恰好有4个点(包含p本身),则p为核心点:

4、边界点:若点 p 的 ε 邻域内点的数量少于 MinPts,但它属于某个核心点的 ε 邻域,则 p 是边界点。如图,设Minpts = 4,已知核心点Q。如图,p点领域内只有两个点,因此p不是核心点,但是p在Q的ε 邻域内,因此p是边界点:

5、噪声点:既不是核心点也不是边界点的点。如下图所示,依然设MinPts = 4,p中只有两个点,小于MinPts,所以p不是核心点。又因为p也不属于其他核心点的ε 邻域领域,p也不是边界点。因此,p是噪声点:

6、直接密度可达:若点 q 在核心点 p 的 ε 邻域内,则称 q 从 p 直接密度可达。

7、间接密度可达:若q1不在核心点p的ε 邻域内,q2在核心点p的ε 邻域内,且q1在q2的ε 邻域内,那么q1与p间接密度可达。

2、算法流程

1、参数设置:指定ε和 MinPts。

2、遍历所有的点:

若点 p 是核心点,创建一个新簇,并递归地将所有从 p 密度可达(直接+间接)的点加入该簇。

若点 p 是边界点或噪声点,暂时标记为未分类。

3、完成分类

3、算法示例

对以下数据点使用DBSCAN算法进行聚类。

这里指定ε = 2, MinPts = 3。

如图,对点A以2为半径画圆,可得A、B、C、D都在圆内,则A为核心点,可得第一个类:{A,B,C,D}。

同理对B、C画圆,B、C都是核心点,由于B、C都在第一个类中了,因此没有新建类别,并且B、C的邻域中没有包含新的点,类别1仍为:{A,B,C,D}。接下来对D以2为半径画圆:

可见,D也是核心点,且D中包含了J,因此类别1进行更新:{A,B,C,D,J}。现在以E为圆心,2为半径画圆:

可以看出,E也是核心点,E、F、G都在圆内。由于此时并没有类别包含E,因此新建一个类2:{E、F、G}。至此,我们已经有两个类别:{A,B,C,D,J}、{E、F、G}。

同理,对F、G画圆,F、G都是核心点,由于F、G都在第二个类中了,因此没有新建类别,并且F、G的邻域中没有包含新的点,类别2仍为:E、F、G}。接下来,以点H为半径,2为圆心画圆:

此时,H的邻域里只有两个点,H不是核心点,并且H此时也不能确定是不是边界点,因此暂时将H标记为噪声点。

接下来,以点I为半径,2为圆心画圆。I的邻域中有三个点:H、I、J。因此I是核心点。由于J已经属于类别1:{A,B,C,D,J},因此I、H均加入类别1,不新建类:{A,B,C,D,J,H,I}。可见,H由噪声点转变为了边界点。

接下来,以J为圆心,2为半径画圆,J为核心点,但J已经在类别1中且没有引入新点,故类别1保持不变。最后以K为圆心,2为半径画圆,K不是核心点也不是边界点,因此K为噪声点。

最终结果为:类别1,{A,B,C,D,J,H,I};类别2,{E、F、G};噪声点:K

4、代码实现

python 复制代码
import numpy as np
from sklearn.cluster import DBSCAN
import matplotlib.pyplot as plt

# 示例数据
X = np.array([
    [1, 1], [2, 1], [1, 3],  # 边界点和噪声点
    [8, 7], [8, 8], [9, 8], [10, 8],  # 簇C1
    [5, 5]  # 噪声点
])

# 应用DBSCAN
dbscan = DBSCAN(eps=1.5, min_samples=2)
labels = dbscan.fit_predict(X)

# 可视化
plt.figure(figsize=(8, 6))
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=100)
plt.title('DBSCAN聚类结果 (ε=1.5, MinPts=2)')
plt.grid(True)
plt.show()

print("聚类标签:", labels)  # 输出: [ 0  0 -1  1  1  1  1 -1]
# -1表示噪声点,0和1表示两个不同的簇
相关推荐
xiaoli23271 小时前
课题学习笔记3——SBERT
笔记·学习·nlp·bert
行然梦实2 小时前
粒子群优化算法(Particle Swarm Optimization, PSO) 求解二维 Rastrigin 函数最小值问题
算法·机器学习·数学建模
XH华2 小时前
C语言第六章函数递归
c语言·开发语言·算法
斯安2 小时前
LRU(Least Recently Used)原理及算法实现
算法
go54631584652 小时前
基于LSTM和GRU的上海空气质量预测研究
图像处理·人工智能·深度学习·神经网络·算法·gru·lstm
亮亮爱刷题2 小时前
算法提升之数论(矩阵+快速幂)
线性代数·算法·矩阵
亿坊电商2 小时前
AI 数字人在处理音频时,如何确保声音的自然度?
人工智能·算法·音视频
愚戏师2 小时前
机器学习(重学版)基础篇(概念与评估)
人工智能·机器学习
向左转, 向右走ˉ2 小时前
随机森林算法原理及优缺点
算法·随机森林·机器学习
ZTLJQ2 小时前
专业Python爬虫实战教程:逆向加密接口与验证码突破完整案例
开发语言·数据结构·爬虫·python·算法