文章目录
K均值聚类
欧几里得距离
欧几里得距离(Euclidean
distance),也称为欧氏距离,是欧几里得空间中两点间的直线距离。在二维和三维空间中,欧几里得距离就是两点之间的实际距离,可以通过勾股定理来计算。在n维空间中,欧几里得距离是两点间各坐标之差的平方和的平方根。对于两点 P ( x 1 , y 1 , . . . , z 1 ) P(x_1, y_1, ..., z_1) P(x1,y1,...,z1) 和 Q ( x 2 , y 2 , . . . , z 2 ) Q(x_2, y_2, ..., z_2) Q(x2,y2,...,z2)
在n维空间中的欧几里得距离 $ d $,可以用以下公式计算:d = ( x 2 − x 1 ) 2 + ( y 2 − y 1 ) 2 + ⋯ + ( z 2 − z 1 ) 2 d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2 + \cdots + (z_2 - z_1)^2} d=(x2−x1)2+(y2−y1)2+⋯+(z2−z1)2
或者更一般地,对于n维空间中的两点 P ( x 1 , x 2 , . . . , x n ) P(x_1, x_2, ..., x_n) P(x1,x2,...,xn) 和 Q ( y 1 , y 2 , . . . , y n ) Q(y_1, y_2, ..., y_n) Q(y1,y2,...,yn),欧几里得距>离 d d d 定义为:
d = ∑ i = 1 n ( y i − x i ) 2 d = \sqrt{\sum_{i=1}^{n} (y_i - x_i)^2} d=i=1∑n(yi−xi)2
欧几里得距离是许多领域中常用的距离度量方式,包括数学、物理学、工程学、统计学、计算机科学和机器学习等。在机器学习中,特别是聚类分析、分类、回归等任务中,欧几里得距离经常被用来衡量样本间的相似度或距离。然而,在特定情况下,如果数据的分布不满足高斯分布或存在异常值,可能会考虑使用其他类型的距离度量,如曼哈顿距离、切比雪夫距离、余弦相似度等。
理论概述
一、定义
K均值聚类(K-Means
Clustering)是一种广泛使用的聚类算法,它基于样本集合的划分进行聚类。具体来说,K均值聚类将样本集合划分为K个子集(或称为类),使得每个样本到其所属类的中心(或称为质心)的距离最小,且每个样本仅属于一个类。这种聚类方式属于硬聚类,即每个样本必须明确地归属于某一类。二、性质
- 迭代求解:K均值聚类是一种迭代求解的聚类分析算法,通过不断迭代来优化聚类结果。
- 基于距离:算法的核心是计算样本与聚类中心之间的距离,并据此进行聚类。
- 硬聚类:每个样本只能被分配到一个聚类中,不能同时属于多个聚类。
- 收敛性:算法会不断迭代,直到满足某个终止条件(如聚类中心不再发生变化或误差平方和局部最小)。
三、计算过程
K均值聚类的计算过程可以归纳为以下几个步骤:
- 选择初始聚类中心:随机选择K个样本作为初始聚类中心。
- 分配样本到聚类:计算每个样本与各个聚类中心之间的距离,将每个样本分配到距离其最近的聚类中心所在的聚类中。
- 重新计算聚类中心:根据当前聚类中的样本,重新计算每个聚类的中心(即计算所有样本的均值作为新的聚类中心)。
- 迭代更新:重复步骤2和步骤3,直到满足终止条件(如聚类中心不再发生变化或达到最大迭代次数)。
四、例子
假设有一个简单的数据集,包含一系列二维空间中的点,我们希望将这些点聚类成两个类。以下是K均值聚类的一个具体例子:
- 选择初始聚类中心:随机选择两个点作为初始聚类中心。
- 分配样本到聚类:计算数据集中每个点到这两个聚类中心的距离,将每个点分配到距离其最近的聚类中心所在的聚类中。
- 重新计算聚类中心:根据当前两个聚类中的点,分别计算它们的均值作为新的聚类中心。
- 迭代更新:重复步骤2和步骤3,直到聚类中心不再发生变化或达到预设的迭代次数。
五、例题
考虑一个具体的数据集,包含以下四个点的坐标(x, y):(1, 2)、(2, 3)、(5, 8)、(8,
7)。现在要求使用K均值聚类算法将这些点聚类成两个类。
- 选择初始聚类中心:假设初始聚类中心为(1, 2)和(8, 7)。
- 分配样本到聚类:
- 点(1, 2)到初始聚类中心(1, 2)的距离为0,到(8, 7)的距离为√[(8-1)^2 + (7-2)^2] = √74。
- 点(2, 3)到(1, 2)的距离较近,因此分配到第一个聚类。
- 点(5, 8)和点(8, 7)到(8, 7)的距离较近,因此分配到第二个聚类。
- 重新计算聚类中心:
- 第一个聚类包含点(1, 2)和(2, 3),新的聚类中心为((1+2)/2, (2+3)/2) = (1.5, 2.5)。
- 第二个聚类包含点(5, 8)和(8, 7),新的聚类中心为((5+8)/2, (8+7)/2) = (6.5, 7.5)。
- 迭代更新:重复分配和重新计算的过程,直到聚类中心不再发生变化。在这个简单的例子中,由于初始选择较为接近最优解,可能一次迭代后聚类中心就不再变化。
具体算法
K均值聚类(K-means
clustering)是一种常用的非监督学习算法,用于将数据集划分为K个簇(clusters),其中K是用户预先定义的簇的数量。算法的目标是将数据点分配到不同的簇中,使得同一簇中的数据点尽可能相似,而不同簇之间的差异尽可能大。1. 定义
K均值聚类是一种基于迭代的聚类方法。其基本思想是通过计算各数据点到簇中心(质心,centroid)的距离来分配数据点,并不断更新质心的位置,直到结果收敛(即不再发生数据点的重新分配或质心的位置不再变化)。
2. 性质
- 非监督学习算法:K均值聚类不需要预先标注的数据集,属于非监督学习的范畴。
- 簇的数量K:算法的用户输入参数K决定了最终的簇的数量。K值的选择对聚类结果影响较大,需要根据具体问题通过经验或其他方法选择。
- 簇的形状:K均值聚类倾向于发现类似于球形(等方差)的簇,这意味着它对簇的形状有一定的假设,如果簇的形状非常复杂或重叠,算法可能表现不佳。
- 初始值敏感性:算法对初始质心的选择敏感,不同的初始选择可能导致不同的聚类结果。
- 算法复杂度:K均值的计算复杂度为O(n * K * d * t),其中n是数据点数量,K是簇的数量,d是数据的维度,t是迭代次数。
3. 计算步骤 K均值聚类的计算过程包括以下几个步骤:
- 选择初始质心:随机选择K个数据点作为初始质心。
- 分配数据点:将每个数据点分配给距离其最近的质心,形成K个簇。
- 更新质心:对于每个簇,计算其所有数据点的均值,并将其作为新的质心。
- 重复步骤2和3:不断重复数据点分配和质心更新的过程,直到质心不再发生变化或达到预定的迭代次数。
4. 例子 假设我们有一组二维数据点:
{ ( 1 , 2 ) , ( 2 , 1 ) , ( 3 , 4 ) , ( 5 , 7 ) , ( 8 , 8 ) , ( 9 , 7 ) } \{(1, 2), (2, 1), (3, 4), (5, 7), (8, 8), (9, 7)\} {(1,2),(2,1),(3,4),(5,7),(8,8),(9,7)}
我们希望将这些数据点分成两个簇(K=2)。
步骤1:随机选择两个数据点作为初始质心,假设选择了(1, 2)和(9, 7)。
步骤2:计算每个数据点到这两个质心的距离,并将其分配到最近的簇。这里可以使用欧几里得距离来计算。
步骤3:更新质心,例如,第一个簇包含(1, 2)和(2, 1),它们的均值为(1.5, 1.5),所以新的质心是(1.5, 1.5)。第二个簇包含(3, 4)、(5, 7)、(8, 8)、(9, 7),它们的均值为(6.25, 6.5)。
步骤4:重复步骤2和3,直到质心不再变化。最终的簇可能会是:
- 簇1:包含(1, 2)、(2, 1)、(3, 4)
- 簇2:包含(5, 7)、(8, 8)、(9, 7)
5. 例题
例题:使用K均值聚类将以下数据点分成3个簇:
{ ( 1 , 2 ) , ( 3 , 4 ) , ( 5 , 6 ) , ( 8 , 8 ) , ( 9 , 10 ) , ( 11 , 12 ) } \{(1, 2), (3, 4), (5, 6), (8, 8), (9, 10), (11, 12)\} {(1,2),(3,4),(5,6),(8,8),(9,10),(11,12)}
解答:
- 选择初始质心:假设随机选择(1, 2)、(8, 8)、(11, 12)作为初始质心。
- 分配数据点:计算每个点到质心的距离,并进行分配。
- 更新质心:计算每个簇的均值,更新质心。
- 重复以上步骤,直到质心不再变化。
通过计算,可以得到最终的聚类结果:
- 簇1:包含(1, 2)
- 簇2:包含(3, 4)、(5, 6)
- 簇3:包含(8, 8)、(9, 10)、(11, 12)
这些簇的质心可能分别为(1, 2)、(4, 5)、(9.33, 10)。
K均值聚类是一种有效且易于实现的聚类算法,但其效果高度依赖于初始值选择以及K值的选择。
julia实现(不调库)
using Statistics
points=[[12.2,151.3,8.3],[3.8,129.34,81.44],[29.31,51.98,37.11],[17.2,51.3,18.3],[32.8,49.74,8.44],[99.31,21.98,57.31],[11.2,35.3,87.3],[23.8,109.34,81.44],[27.31,101.98,87.11],[87.23,63.22,19.32],[47.29,121.43,29.43]]
k=3
group_points=Dict{Int64,Vector{Vector{Float64}}}()
for i in 1:k
group_points[i]=[]
end
function getDistance(x::Vector{Float64},y::Vector{Float64})
return sqrt(sum((y-x).^2))
end
function getRandIndex(n,k)::Vector{Int}
ids=collect(1:n)
rand_i=[]
for i in 1:k
idx=rand(1:n)
push!(rand_i,ids[idx])
deleteat!(ids,idx)
n=n-1
end
return rand_i
end
function getRandZhiXing(n,k)
return points[getRandIndex(n,k)]
end
function xyDistCompare(x,y)
return x[3]<y[3]
end
function getNearpoints(points::Vector{Vector{Float64}},zhixing::Vector{Vector{Float64}})::Vector{Tuple{Int64, Int64, Float64}}
dist_lst=[(x_i,y_i,getDistance(zhixing[x_i],points[y_i])) for x_i in 1:length(zhixing) for y_i in 1:length(points)]
sort!(dist_lst,lt=xyDistCompare)
return dist_lst
end
function updateGroups(points::Vector{Vector{Float64}},zhixing::Vector{Vector{Float64}})
y_have=[]
global group_points
is_zhixing_change=false
for i in 1:length(zhixing)
if length(group_points[i])>1
new_zhixing=mean(group_points[i])
if sum(abs.(new_zhixing-zhixing[i])) >0
zhixing[i]=new_zhixing
is_zhixing_change=true
end
else
is_zhixing_change=true
end
end
if is_zhixing_change
for i in 1:length(zhixing)
group_points[i]=[]
end
else
return zhixing
end
near_points=getNearpoints(points,zhixing)
for npoint in near_points
x_i,y_i,dst=npoint
if !(y_i in y_have)
push!(group_points[x_i],points[y_i])
push!(y_have,y_i)
end
end
updateGroups(points,zhixing)
end
zhixing=getRandZhiXing(length(points),k)
zhixing=updateGroups(points,zhixing)
for i in 1:k
println(zhixing[i],"===>",group_points[i])
end
[22.6275, 47.08, 37.787499999999994]===>[[29.31, 51.98, 37.11], [17.2, 51.3, 18.3], [32.8, 49.74, 8.44], [11.2, 35.3, 87.3]]
[93.27000000000001, 42.6, 38.315]===>[[87.23, 63.22, 19.32], [99.31, 21.98, 57.31]]
[22.88, 122.67800000000003, 57.544000000000004]===>[[23.8, 109.34, 81.44], [3.8, 129.34, 81.44], [27.31, 101.98, 87.11], [47.29, 121.43, 29.43], [12.2, 151.3, 8.3]]
* Terminal will be reused by tasks, press any key to close it.
参考文献
1.文心一言
2.chatgpt