机器学习之k-means算法

k-means算法

简介

        k-means算法是一种聚类算法,所谓聚类,即根据相似性原则,将具有较高相似度的数据对象划分至同一类簇,将具有较高相异度的数据对象划分至不同类簇。聚类与分类最大的区别在于,聚类过程为无监督过程,即待处理数据对象没有任何先验知识,而分类过程为有监督过程,即存在有先验知识的训练数据集。
        由于k-means聚类算法需要检测两个对象间的相似性,但对象数据是无标签的,因此很难定义相似性。我们可以按照自己的实验目的定义不同的相似性规则,然后按照规则去计算数据对象之间的相似性。
        比如,假设数据对象集是一组二维数据,{(xi,yi),0<i<N}。假设这些数据中有k (k<N) 个数据是精确的,其余数据分别是这k个数据的近似值,则当我们希望将这些数据分为k组且每组包含一个精确数据和其对应的近似值时 (并不是求出k个精确值,因为无标签,我们不知道那些数据是精确的),数据对象之间的相似性可定义为对象数据之间的欧式距离*(两点间的距离)*,欧式距离越小,则相似性越高,数据之间越相近,更有可能划分到同一组,欧式距离越大,则相似性越小,数据之间越远,更有可能被划分到不同组中,需要注意的是当这k个数据之间的欧式距离很小时,这种相似性定义方法不能帮助我们得到正确的k个分组。假设数据对象中的x表示时间,当我们想要将对应时间相近的数据对象分到一组时,我们不需要再考虑y,此时相似性可定义为x之间的差距|xi-xj|。

种类

  1. 水平聚类:分区彼此独立
    水平
  2. 层次聚类
    层次

原理

假设需要将数据分为k个类,以欧式距离作为相似性评判标准。

  1. 随机选取k个数据作为初始k个类簇的质心。
  2. 将数据集中的每个数据di ( di=(xi,yi) ) 拿出来与每个质心计算欧式距离,如果di与质心kj的欧式距离最小,则将di划分到第j个类簇中。
  3. 计算每个类簇中的平均值,将此平均值作为此类簇的新的质心。
  4. 如果每个类簇中新质心与之前的质心差值足够小,则将k个类簇作为k个组输出;如果新质心与之前的质心差值不满足要求,则转到第2步进行迭代更新。

运行过程示例

proceedings

目标

通过k-means聚类算法,我们得到了k个组,我们希望组内数据之间相似度较高,组间数据之间相似度较低。

特点

  1. 优点:算法实现简单
  2. 缺点:需要用户指定分组的个数; 聚类结果对初始类簇中心的选取较为敏感; 容易陷入局部最优状况。

k-means算法实验

实验内容

1.描述
        在这个练习中,你将使用k-means算法通过减少图像包含的颜色数量来压缩图像。首先,下载data6.zip并将其内容加载到Matlab/Octave工作目录中。
        照片来源:本练习使用的bird照片属于Frank Wouters,经其许可使用。
2. 图像表示
        这个练习的数据包含一个538像素×538像素的TIFF图像,名为bird_large.tiff。它看起来像下面的图片。
p
        这幅图像的直接24位颜色表示中,每个像素由三个8位数字(从0到255)表示,它们指定了红、绿和蓝的强度值。我们的这张照片包含了上千种颜色,但我们想把这个数字减少到16种。通过这种减少,只存储图像中16种颜色的RGB值,这样我们可以更高效地表示这张照片。
        在这个练习中,您将使用k-means算法将颜色数量减少到k=16。也就是说,你将计算16种颜色作为聚类中心,并将图像中的每个像素替换为最近的聚类中心颜色。
        因为计算聚类538×538图像对电脑很耗时,你将在128×128的bird_small.tiff上运行k-means算法。一旦你得到了小图像上的聚类中心,就可以使用这16种聚类中心颜色替换大图像中的像素。
3. K-means in Matlab/Octave
(1)在Matlab/Octave中,用以下命令将小图像加载到程序中:

A = double(imread('bird_small.tiff'));

        这将创建一个三维矩阵A,其前两个索引标识像素位置,最后一个索引表示红色、绿色或蓝色。例如,A(50,33,3)给出了像素在位置y=50,x=33处的蓝色强度。(首先给出Y位置,但在我们的示例中这并不重要,因为X和Y尺寸具有相同的尺寸)。
        你的任务是从该图像计算16个类簇中心,每个中心是一个长度为3的向量,包含一组RGB值。k-means算法适用于解决这个问题。
(2)当k个聚类中心收敛后,将大图像加载到程序中,并用从小图像中找到的最接近质心的颜色替换其每个像素颜色。
        重新计算大图像后,可以按以下方式显示和保存图像:

%Display
imshow(uint8(round(large_image)));
%Save image
imwrite(uint8(round(large_image)),'bird_kmeans.tiff');

实验代码

small = double(imread('E:\machine_learning\experiment\exp6\data6\ex8Data\bird_small.tiff'));
%16个中心的颜色
cr = zeros(1,16);
cg = zeros(1,16);
cb = zeros(1,16);
size_small = size(small,1);
%伪随机取16种颜色
for i=1:16
    position = 7*i;
    cr(1,i) = small(position,position,1);
    cg(1,i) = small(position,position,2);
    cb(1,i) = small(position,position,3);
end

%为每个像素点初始一个空间,保存其对应个类簇号
s_matrix = zeros(size_small, size_small);
%获取16个聚类
%迭代100次,100次时两个数据中心距离足够近。
for num = 1:100
    for j=1:128
        for k=1:128
            cmin = inf;%像素颜色数据与16个聚类中心最小的距离,初始为无穷大
            for i=1:16
                r = small(j,k,1);
                g = small(j,k,2);
                b = small(j,k,3);
                dr = r-cr(1,i);
                dg = g-cg(1,i);
                db = b-cb(1,i);
                c = dr*dr+dg*dg+db*db;%距离,没有求根,因为只比较大小,对具体数值无要求
                if cmin > c
                    cmin = c;%更新最小距离
                    s_matrix(j,k) = i;%更新所属类簇号
                end
            end
        end
    end

    %更新聚类中心
    count = zeros(1,16);
    for k = 1:16
        for i=1:128
            for j=1:128
                if(s_matrix(i,j) == k)
                    count(1,k) = count(1,k)+1;%计算类中有几个点
                end
            end
        end
    end
    red = zeros(1,16);
    green = zeros(1,16);
    blue = zeros(1,16);
    for k = 1:16
        for i=1:128
            for j=1:128
                if(s_matrix(i,j) == k)%将一个类中的所有值都加起来
                    red(1,k) = red(1,k) + small(i,j,1);
                    green(1,k) = green(1,k) + small(i,j,2);
                    blue(1,k) = blue(1,k) + small(i,j,3);
                end
            end
        end
        cr(1,k) = red(1,k)/count(1,k);%求平均数,来作为新的聚类中心
        cg(1,k) = green(1,k)/count(1,k);
        cb(1,k) = blue(1,k)/count(1,k);
    end
end

%压缩small图片
for k = 1:16
    for i = 1:size_small
        for j =1:size_small
            if(s_matrix(i,j) == k)
                small(i,j,1) = cr(1,k);
                small(i,j,2) = cg(1,k);
                small(i,j,3) = cb(1,k);
            end
        end
    end
end
%显示图片
%imshow(uint8(round(small)));
%保存图片
imwrite(uint8(round(small)),'bird_small.jpg');

%压缩large图片
large = double(imread('E:\machine_learning\experiment\exp6\data6\ex8Data\bird_large.tiff'));
size_large = size(large, 1);
l_matrix = zeros(size_large, size_large);
for i = 1:size_large
    for j =1:size_large
        dmin = inf;
        for k=1:16
            dr = large(i,j,1)-cr(1,k);
            dg = large(i,j,2)-cg(1,k);
            db = large(i,j,3)-cb(1,k);
            distance = dr*dr+dg*dg+db*db;
            if dmin > distance
                dmin = distance;
                l_matrix(i,j) = k;
            end
        end
    end
end
for k = 1:16
    for i = 1:size_large
        for j =1:size_large
            if(l_matrix(i,j) == k)
                large(i,j,1) = cr(1,k);
                large(i,j,2) = cg(1,k);
                large(i,j,3) = cb(1,k);
            end
        end
    end
end
%显示图片
imshow(uint8(round(large)));
%保存图片
imwrite(uint8(round(large)),'bird_large.jpg');

实验结果

原图像:
p1
压缩后的图像
p2

实验数据和代码

mathlab实验数据和代码下载
java实现的对数据集聚类的算法代码下载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值