人工智能与机器学习原理精解【13】

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=(x2x1)2+(y2y1)2++(z2z1)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=1n(yixi)2

欧几里得距离是许多领域中常用的距离度量方式,包括数学、物理学、工程学、统计学、计算机科学和机器学习等。在机器学习中,特别是聚类分析、分类、回归等任务中,欧几里得距离经常被用来衡量样本间的相似度或距离。然而,在特定情况下,如果数据的分布不满足高斯分布或存在异常值,可能会考虑使用其他类型的距离度量,如曼哈顿距离、切比雪夫距离、余弦相似度等。

理论概述

一、定义

K均值聚类(K-Means
Clustering)是一种广泛使用的聚类算法,它基于样本集合的划分进行聚类。具体来说,K均值聚类将样本集合划分为K个子集(或称为类),使得每个样本到其所属类的中心(或称为质心)的距离最小,且每个样本仅属于一个类。这种聚类方式属于硬聚类,即每个样本必须明确地归属于某一类。

二、性质
  1. 迭代求解:K均值聚类是一种迭代求解的聚类分析算法,通过不断迭代来优化聚类结果。
  2. 基于距离:算法的核心是计算样本与聚类中心之间的距离,并据此进行聚类。
  3. 硬聚类:每个样本只能被分配到一个聚类中,不能同时属于多个聚类。
  4. 收敛性:算法会不断迭代,直到满足某个终止条件(如聚类中心不再发生变化或误差平方和局部最小)。
三、计算过程

K均值聚类的计算过程可以归纳为以下几个步骤:

  1. 选择初始聚类中心:随机选择K个样本作为初始聚类中心。
  2. 分配样本到聚类:计算每个样本与各个聚类中心之间的距离,将每个样本分配到距离其最近的聚类中心所在的聚类中。
  3. 重新计算聚类中心:根据当前聚类中的样本,重新计算每个聚类的中心(即计算所有样本的均值作为新的聚类中心)。
  4. 迭代更新:重复步骤2和步骤3,直到满足终止条件(如聚类中心不再发生变化或达到最大迭代次数)。
四、例子

假设有一个简单的数据集,包含一系列二维空间中的点,我们希望将这些点聚类成两个类。以下是K均值聚类的一个具体例子:

  1. 选择初始聚类中心:随机选择两个点作为初始聚类中心。
  2. 分配样本到聚类:计算数据集中每个点到这两个聚类中心的距离,将每个点分配到距离其最近的聚类中心所在的聚类中。
  3. 重新计算聚类中心:根据当前两个聚类中的点,分别计算它们的均值作为新的聚类中心。
  4. 迭代更新:重复步骤2和步骤3,直到聚类中心不再发生变化或达到预设的迭代次数。
五、例题

考虑一个具体的数据集,包含以下四个点的坐标(x, y):(1, 2)、(2, 3)、(5, 8)、(8,
7)。现在要求使用K均值聚类算法将这些点聚类成两个类。

  1. 选择初始聚类中心:假设初始聚类中心为(1, 2)和(8, 7)。
  2. 分配样本到聚类
    • 点(1, 2)到初始聚类中心(1, 2)的距离为0,到(8, 7)的距离为√[(8-1)^2 + (7-2)^2] = √74。
    • 点(2, 3)到(1, 2)的距离较近,因此分配到第一个聚类。
    • 点(5, 8)和点(8, 7)到(8, 7)的距离较近,因此分配到第二个聚类。
  3. 重新计算聚类中心
    • 第一个聚类包含点(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)。
  4. 迭代更新:重复分配和重新计算的过程,直到聚类中心不再发生变化。在这个简单的例子中,由于初始选择较为接近最优解,可能一次迭代后聚类中心就不再变化。

具体算法

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均值聚类的计算过程包括以下几个步骤:

  1. 选择初始质心:随机选择K个数据点作为初始质心。
  2. 分配数据点:将每个数据点分配给距离其最近的质心,形成K个簇。
  3. 更新质心:对于每个簇,计算其所有数据点的均值,并将其作为新的质心。
  4. 重复步骤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. 选择初始质心:假设随机选择(1, 2)、(8, 8)、(11, 12)作为初始质心。
  2. 分配数据点:计算每个点到质心的距离,并进行分配。
  3. 更新质心:计算每个簇的均值,更新质心。
  4. 重复以上步骤,直到质心不再变化。

通过计算,可以得到最终的聚类结果:

  • 簇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

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值