继续之前关于机器学习的笔记,此次为无监督学习的算法分享。
类比于之前的有监督学习而言,无监督学习最大的特点在于训练集中不会给出正确的分类,即训练样本中并没有对样本进行划分,需要算法自己学习,找出其中哪些样本是属于一类的。如下图所示
这种自动分类算法又称为聚类算法,是一种通过学习进行自动分类的算法。
聚类算法中最为常用的为K-means算法,下面来介绍这种算法的原理。
首先原始的数据集如下所示。
随后随机生成两个聚类中心点,用于将数据集初步分为两类。如下所示。
其中,分类方法为,分别取出数据集中的所有点,计算每个点到达两个中心点的距离,如果该点距离红色中心点近则该点为红色,相反为蓝色。最终结果如上图所示。随后,移动中心点到下图。
移动的算法为,计算所有的红色点的横纵坐标平均值,并将中心点移动到平均值位置,即分别将中心点向自己分类的中心移动。然后重复上述步骤重新对所有的点进行染色。 如下图所示。
重复以上的步骤直至中心点不再变动,就会发现K-means算法已经将训练集分成了红蓝两类。如下图所示
首先是将数据集根据距离中心点的距离进行划分,本例子中将数据集划分成三类,因此初始化过程中有三个中心点。
load('ex7data2.mat');
% 选取中心点个数
K = 3;
initial_centroids = [3 3; 6 2; 8 5]; % 三个中心点的坐标
随后根据数据集中的各个点到三个中心点的距离大小来对数据集进行分类。其中 idx 是一个和数据集一样大的列矩阵,用于记录对应数据集中的每个点被划分的中心点。1代表第一个中心点,2代表第二个中心点,3代表第三个。
function idx = findClosestCentroids(X, centroids)
K = size(centroids, 1); % 中心点个数
idx = zeros(size(X,1), 1); % 用于记录每个数据所属的中心点
m = size(idx, 1);
for i = 1:m
min = 100000;
flag = 0;
for j = 1:K
% 计算该点与中心点的距离的平方
temp = (X(i,1)-centroids(j,1)).^2 + (X(i,2)-centroids(j,2)).^2;
if temp <= min
min = temp;
flag = j;
end
end
idx(i,1) = flag;
end
end
然后计算中心点的移动位置。计算中心点所在群体的中心位置,并将其移动到该位置。方法分别计算中心点所在的群的所有点的坐标和,然后用和除以群数量得到平均值。
function centroids = computeCentroids(X, idx, K)
[m n] = size(X);
centroids = zeros(K, n);
num1 = 0;
num2 = 0;
num3 = 0;
sum1 = [0;0];
sum2 = [0;0];
sum3 = [0;0];
flag = 1;
for i = 1:size(idx, 1)
if idx(i,1) == 1
num1 = num1 + 1;
sum1 = sum1 + [X(i,1);X(i,2)];
elseif idx(i,1) == 2
num2 = num2 + 1;
sum2 = sum2 + [X(i,1);X(i,2)];
elseif idx(i,1) == 3
num3 = num3 + 1;
sum3 = sum3 + [X(i,1);X(i,2)];
end
end
u1 = sum1 ./ num1;
u2 = sum2 ./ num2;
u3 = sum3 ./ num3;
centroids(1, 1) = u1(1, 1);
centroids(1, 2) = u1(2, 1);
centroids(2, 1) = u2(1, 1);
centroids(2, 2) = u2(2, 1);
centroids(3, 1) = u3(1, 1);
centroids(3, 2) = u3(2, 1);
end
通过多次循环以上两个算法,并观察其变化过程。
function [centroids, idx] = runkMeans(X, initial_centroids, max_iters, plot_progress)
if ~exist('plot_progress', 'var') || isempty(plot_progress)
plot_progress = false;
end
if plot_progress
figure;
hold on;
end
% Initialize values
[m n] = size(X);
K = size(initial_centroids, 1);
centroids = initial_centroids;
previous_centroids = centroids;
idx = zeros(m, 1);
% Run K-Means
for i=1:max_iters
% Output progress
fprintf('K-Means iteration %d/%d...\n', i, max_iters);
if exist('OCTAVE_VERSION')
fflush(stdout);
end
% For each example in X, assign it to the closest centroid
idx = findClosestCentroids(X, centroids);
% Optionally, plot progress here
if plot_progress
plotProgresskMeans(X, centroids, previous_centroids, idx, K, i);
previous_centroids = centroids;
fprintf('Press enter to continue.\n');
pause;
end
% Given the memberships, compute new centroids
centroids = computeCentroids(X, idx, K);
end
% Hold off if we are plotting progress
if plot_progress
hold off;
end
end
结果如下图所示
可以看出中心点一点一点向自身群体的中心移动,最终将数据集划分成三类。