K均值算法

  上一期介绍了机器学习中的监督式学习,并用了离散回归与神经网络模型算法来解决手写数字的识别问题。今天我们介绍一种机器学习中的非监督式学习算法——K均值算法。

  所谓非监督式学习,是一种与监督式学习相对的算法归类,是指样本并没有一个与之对应的“标签”。例如上一期中的识别手写数字照片的例子,样本是照片的像素数据,而标签则是照片代表的数字。非监督式学习因为没有这个标签,因此就没有对样本的一个准确的“答案”。非监督式学习主要是用来解决样本的聚类问题。

  K均值算法是一种迭代求解的聚类分析算法,其步骤为:

  1. 随机选取K个对象作为初始的聚类中心
  2. 计算每个对象与各个聚类中心之间的距离
  3. 把每个对象分配给距离它最近的聚类中心
  4. 将同一聚类中的对象的平均值作为新的聚类中心
  5. 从第2步开始循环,直到聚类中心不再变化

代码实现

随机初始化

% 样本随机排列
randidx = randperm(size(X, 1));
% 取前K个随机样本作为聚类中心
centroids = X(randidx(1:K), :);

  其中X为样本矩阵,每一行为一个样本,每一列为样本的维度,centroids就是随机出的K个作为聚类中心的样本矩阵。

分配聚类中心

% 遍历所有样本
for i = 1:size(X, 1)
distance = 9999999999;
for j = 1:K
% 距离公式:A(a1, a2)与B(b1, b2)之间的距离为根号下(a1-b1)^2 + (a2 - b2)^2
dist = sum((X(i, :) - centroids(j, :)) .^ 2);
if dist < distance
idx(i) = j;
distance = dist;
end
endfor
endfor

  通过两层循环,第一层为遍历所有样本,找到每个样本所属的聚类中心。第二层循环为遍历所有聚类中心,计算样本与聚类中心的距离,找出与类聚中心最小的距离,将该类聚中心作为样本的类聚中心。

更新聚类中心

  • 方式一:循环样本
count = zeros(K, 1);
for i = 1 : m
id = idx(i);
% 累加该聚类中心下的所有样本
centroids(id, :) = centroids(id, :) + X(i, :);
count(id) = count(id) + 1;
endfor
% 均值作为新的聚类中心
centroids = centroids ./ count;
  • 方式二:循环类聚中心(效率更高)
for i = 1:K
% 直接通过mean函数计算均值
centroids(i,:) = mean(X(idx==i,:),1);
end

  可以看到,通过matlab内置的mean函数,可以更加便捷的计算出矩阵对应行的均值,并且计算过程也会比累加的方式执行更加高效。

步骤演示

  如上图所示,有一些无标签的二维坐标点。通过一些基本的判断,我们大致可以将上述的数据分为左上、中右部、左下三个聚类,但是有些中间位置的点可能不太好划分,如下图所示。

  但是如何才能让机器为我们做出分类呢?机器又如何决策这些处于中间位置的点呢?于是我们来运行上述已经写好的K均值算法。

  如图所示,是运行了K均值算法的第一步:随机初始化后的聚类。可以看到图中的绿色、蓝色、红色分布,因为聚类中心点是随机的,初始的聚类中心并不正确,于是我们继续运行K均值算法的后面步骤。

  以绿色的聚类来举例,绿色的聚类通过一次均值计算之后,新的聚类中心点上升了许多。根据新的聚类中心点,再计算样本归属时,则会判断出下方的点已经不再属于绿色,而属于蓝色,因此就对之前的聚类进行了修正。

  再看之前比较有疑问的绿色聚类与红色聚类之间的中间点(灰色框中所示),这几个点在感官上距离两个聚类都差不多,但根据与聚类中心点的计算对比,从数值上计算得出这几个点实际上属于红色聚类。

  进行多次循环之后,聚类中心点不再变化,则说明K均值算法应用成功,分出了3个聚类并用不同颜色表示。

图片压缩

  我们知道,图片是由许多像素点组成的,而每个像素点需要有RGB值。所谓RGB值是一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的。每个颜色的强度值是0-255,刚好是1个字节的大小。而3个颜色就是3个字节的大小,所以每个像素点所占大小为3字节,即24比特(故又称24位真彩色图,有1677万多色)。

  以一张700*700像素的图为例,一共有490,000个像素点,每个像素点占24比特,合计11,760,000比特。如果能够应用K均值算法来实现图片的压缩呢?

  压缩的前提数据有冗余,或者近似冗余。一张图片中数十万的像素点,肯定有许多像素点的RGB值是比较相似的,即图片中可能有某些位置都是同一个颜色。那么就可以应用K均值算法,将图片分成许多个聚类,用一张聚类表来存储每个聚类的颜色值,再用一张像素表来存储每个像素所在的聚类,就可以达到压缩的目的。

  我选择了K=16,即有16个聚类,则原图片从1677万色变成了16色。聚类表占用的大小为16 * 24bit,即384比特。16个聚类是2的4次方只需要4个比特就可以存储聚类信息,则像素表的大小为490,000 * 4,即1,960,000。总大小为1,960,000+384=1,960,384比特,通过计算可得(压缩后大小/压缩前大小),压缩率为16.67%。即如果是100KB的图片,压缩后的大小只有16.67KB。

图片数据处理

% 调用imread读取图片
A = double(imread('test.png'));
% 将像素值处理到0-1
A = A / 255;
% 将数据从3维降到2维
img_size = size(A);
X = reshape(A, img_size(1) * img_size(2), 3);

获取聚类中心

% 随机初始化
initial_centroids = kMeansInitCentroids(X, K);
% 调用之前写好的K均值算法
[centroids, idx] = runkMeans(X, initial_centroids, max_iters);

压缩

% 调用之前写好的“分配聚类中心”
idx = findClosestCentroids(X, centroids);

解压缩

% 通过聚类表获取原始像素值
X_recovered = centroids(idx,:);
% 将数据升至3维
X_recovered = reshape(X_recovered, img_size(1), img_size(2), 3);

压缩效果展示

  可以看到,压缩后的图片仍然具有较清晰的轮廓,只是色彩没有那么丰富(只有16种颜色),某些细节有一些失真,但是不影响图片的整体表达。

总结

  1. K均值算法是最常用也是最简单的非监督式学习聚类算法
  2. 第一步的随机聚类中心对聚类结果有一定影响,因此可以运行多次以达到比较好的聚类结果
  3. 将聚类算法的思想作用在图片上,可以达到图片压缩的目的。
  4. 如果想要有更好的图片质量,可以提高聚类数量K,但这样会得到较差的压缩率,需要在实践中以平衡。

使用K均值算法进行图片压缩的更多相关文章

  1. 4.K均值算法--应用

    1. 应用K-means算法进行图片压缩 读取一张图片 观察图片文件大小,占内存大小,图片数据结构,线性化 用kmeans对图片像素颜色进行聚类 获取每个像素的颜色类别,每个类别的颜色 压缩图片生成: ...

  2. 4.K均值算法应用

    一.课堂练习 from sklearn.cluster import KMeans import matplotlib.pyplot as plt import numpy as np from sk ...

  3. 机器学习之K均值算法(K-means)聚类

    K均值算法(K-means)聚类 [关键词]K个种子,均值 一.K-means算法原理 聚类的概念:一种无监督的学习,事先不知道类别,自动将相似的对象归到同一个簇中. K-Means算法是一种聚类分析 ...

  4. 聚类分析K均值算法讲解

    聚类分析及K均值算法讲解 吴裕雄 当今信息大爆炸时代,公司企业.教育科学.医疗卫生.社会民生等领域每天都在产生大量的结构多样的数据.产生数据的方式更是多种多样,如各类的:摄像头.传感器.报表.海量网络 ...

  5. 聚类算法:K-means 算法(k均值算法)

    k-means算法:      第一步:选$K$个初始聚类中心,$z_1(1),z_2(1),\cdots,z_k(1)$,其中括号内的序号为寻找聚类中心的迭代运算的次序号. 聚类中心的向量值可任意设 ...

  6. 一句话总结K均值算法

    一句话总结K均值算法 核心:把样本分配到离它最近的类中心所属的类,类中心由属于这个类的所有样本确定. k均值算法是一种无监督的聚类算法.算法将每个样本分配到离它最近的那个类中心所代表的类,而类中心的确 ...

  7. 聚类--K均值算法:自主实现与sklearn.cluster.KMeans调用

    1.用python实现K均值算法 import numpy as np x = np.random.randint(1,100,20)#产生的20个一到一百的随机整数 y = np.zeros(20) ...

  8. 【机器学习】K均值算法(I)

    K均值算法是一类非监督学习类,其可以通过观察样本的离散性来对样本进行分类. 例如,在对如下图所示的样本中进行聚类,则执行如下步骤 1:随机选取3个点作为聚类中心. 2:簇分配:遍历所有样本然后依据每个 ...

  9. Bisecting KMeans (二分K均值)算法讲解及实现

    算法原理 由于传统的KMeans算法的聚类结果易受到初始聚类中心点选择的影响,因此在传统的KMeans算法的基础上进行算法改进,对初始中心点选取比较严格,各中心点的距离较远,这就避免了初始聚类中心会选 ...

随机推荐

  1. 【tensorflow】】模型优化(一)指数衰减学习率

    指数衰减学习率是先使用较大的学习率来快速得到一个较优的解,然后随着迭代的继续,逐步减小学习率,使得模型在训练后期更加稳定.在训练神经网络时,需要设置学习率(learning rate)控制参数的更新速 ...

  2. 2011-04-21 运程连Oracle的方法

    oracle无法远程连接重要原因,即使防火墙开放1521端口, 但是返回包可能是随机端口,所以仍有可能被防火墙阻止. 解决方法: 在注册表中增加一个字符串值如下.可解决 花费两天找到的方法 [HKEY ...

  3. 手动实现如何从H264流中提取SPS/PPS信息

    1,代码比较简单,可以直接用了.流的第一个NALU一定是SPS void get_sps_pps_nalu(uint8_t *data, int len, std::vector<uint8_t ...

  4. C# 比较两张图片是否完全相同

    本文演示如何比较两张图片是否完全相同. (注意:如果是比较两张图片是否相似,则比较复杂,涉及到机器学习) 方法一:把图片保存到内存流中,然后转化成 Base64 字符串进行比较 using Syste ...

  5. 原生sql和 TP sql怎么关联?

    整合后

  6. Java一行代码可声明多个同类变量

    Java支持一句语句声明多个同类变量. Example: String a = "Hello", c = "hello"; int x = 5, y = 5;

  7. H3C PPP基本配置

  8. Python--day26--类方法和静态方法

    类方法: 静态方法:

  9. java List接口中常用类

    Vector:线程安全,但速度慢,已被ArrayList替代. ArrayList:线程不安全,查询速度快. LinkedList:链表结构,增删速度快.取出List集合中元素的方式: get(int ...

  10. Linux 内核驱动结构嵌入

    如同大部分驱动核心结构的情形, device_driver 结构常常被发现嵌到一个更高级的, 总 线特定的结构. lddbus 子系统不会和这样的趋势相反, 因此它已定义了它自己的 ldd_drive ...