如何理解Matlab内置函数"kmeans"?

How to understand the Matlab build in function "kmeans"?

假设我有一个矩阵A,它的大小是2000*1000 double。然后我申请 Matlab 内置函数 "kmeans" 到矩阵 A.

k = 8;
[idx,C] = kmeans(A, k, 'Distance', 'cosine');

我得到C = 8*1000 doubleidx = 2000*1 double,取值从1到8; 根据文档,C returns k-by-p (8 by 1000) 矩阵中的 k 个聚类质心位置。并且 idx returns 一个 n-by-1 vector 包含每个观察的聚类索引。 我的问题是:

1) 我不知道如何理解 C 的质心位置。位置应该表示为 (x,y),对吗?如何正确理解矩阵C

2) 最后的中心是什么c1, c2,...,ck?它们只是值还是位置?

3) 对于每一个cluster,如果我只想得到最接近这个cluster中心的vector,如何计算得到呢?

谢谢!

好的,在我们真正深入细节之前,让我们先简要概述一下K——聚类是什么意思。


k-means clustering 的工作原理是,对于您拥有的某些数据,您想将它们分组到 k 组中。您最初在数据中选择 k 运行dom 点,这些点将具有来自 1,2,...,k 的标签。这些就是我们所说的 质心 。然后,您确定其余数据与每个点的接近程度。然后,您将这些点分组,以便无论哪个点最接近这些 k 点中的任何一个,您都将这些点分配给属于该特定组 (1,2,...,k)。之后,对于每个组的所有点,更新 centroids,它实际上被定义为每个组的代表点。对于每个组,您计算每个 k 组中所有点的平均值。这些成为下一次迭代的 new 质心。在下一次迭代中,您确定数据中的每个点与 每个质心 的接近程度。您不断迭代并重复此行为,直到质心不再移动,或者它们移动得很少。


如何在 MATLAB 中使用 kmeans 函数,假设您有一个数据矩阵(A 在您的情况下),它是 ar运行ged 这样每一行都是一个样本,每一列都是样本的一个特征/维度。例如,我们可以有 N x 2N x 3 笛卡尔坐标数组,无论是 2D 还是 3D。在彩色图像中,我们可以有 N x 3 个数组,其中每一列都是图像中的一个颜色分量 - 红色、绿色或蓝色。

如何在 MATLAB 中调用 kmeans 的方式如下:

[IDX, C] = kmeans(X, K);

X 是我们谈到的数据矩阵,K 是您希望看到的簇/组的总数以及输出 IDXC分别是 indexcentroid 矩阵。 IDX 是一个 N x 1 数组,其中 N 是您放入函数中的样本总数。 IDX 中的每个值都会告诉您 哪个质心 X 中的样本/行与特定质心最匹配。您还可以覆盖用于测量点之间距离的距离度量。默认情况下,这是欧氏距离,但您在调用中使用了余弦距离。

CK 行,其中每行都是一个质心。因此,对于笛卡尔坐标,这将是一个 K x 2K x 3 数组。因此,在计算 k-means 时,您会将 IDX 解释为告诉该点最接近哪个组/质心。因此,如果我们得到一个点的值 IDX=1,这意味着该点与第一个质心最匹配,即 C 的第一行。同样,如果我们得到一个点的值 IDX=1,这意味着该点与第三个质心最匹配,即 C 的第三行。


现在回答你的问题:

  1. 我们刚刚谈到了 CIDX 所以这应该很清楚了。
  2. 最终的中心存储在C中。每行给你一个代表一组的质心/中心。
  3. 听起来你想在数据中找到离每个聚类最近的点,除了实际的质心本身。如果您使用 knnsearch 通过给出一组点执行 K 最近邻搜索并输出数据中接近查询点的 K 最近点,这很容易做到。因此,您提供集群作为输入,您的数据作为输出,然后使用 K=2 并跳过第一点。第一个点的距离为 0,因为这将等于质心本身,第二个点将为您提供距离集群最近的最近点。

    假设您已经运行kmeans:

    ,您可以通过以下方式做到这一点
    out = knnsearch(A, C, 'k', 2);
    out = out(:,2);
    

    你 运行 knnsearch,然后抛出最近的点,因为它的距离基本上为 0。第二列是你所追求的,它给你最近的点到不包括实际质心的集群。 out 将为您提供数据矩阵 A 中最接近每个质心的点。要获得实际分数,请执行以下操作:

    pts = A(out,:);
    

希望对您有所帮助!

在回答这三个部分之前,我将只解释一下 MATLAB 解释 k-means (http://www.mathworks.com/help/stats/kmeans.html) 时使用的语法。

  • A 是您的数据矩阵(在 link 中表示为 X)。有 n 行(在本例中为 2000),代表您拥有的 observations/data 点数。还有 p 列(在本例中为 1000),表示每个数据点具有的 "features" 个数。例如,如果您的数据由二维点组成,那么 p 将等于 2.
  • k 是您要将数据分组到的聚类数。根据您提供的 C 的维度,k 必须是 8。

现在我分三部分回答:

  1. C 矩阵的维度为 k x p。每行代表一个质​​心。质心位置根本不必是 (x, y)。质心位置的尺寸等于 p。换句话说,如果您有 2D 点,则可以将质心绘制为 (x, y)。如果您有 3D 点,则可以将质心绘制为 (x, y, z)。由于 A 中的每个数据点都有 1000 个特征,因此您的质心有 1000 个维度。
  2. 如果不知道您的数据到底是什么,这有点难以解释。质心当然不仅仅是值,也不一定是位置。如果您的数据 A 是坐标点,您当然可以将质心表示为位置。但是,我们可以更普遍地看待它。如果您有一个聚类质心 i 和与该质心分组的数据点 v,则质心将代表与其聚类中的数据点最相似的数据点。希望这是有道理的,如有必要,我可以给出更清楚的解释。
  3. k-means方法实际上给了我们一个很好的方法来完成这个。该函数实际上有 4 个可能的输出,但我将重点关注第 4 个,我将其称为 D:

    [idx,C,sumd,D] = kmeans(A, k, 'Distance', 'cosine');
    

    D 的维度为 n x k。对于数据点 iD 矩阵中的行 i 给出了从该点到每个质心的距离。因此,对于每个质心,您只需找到最接近它的数据点,然后 return 对应的数据点。如果您需要,我可以提供短代码。

此外,只是一个小费。您可能应该使用 kmeans++ 初始化质心的方法。它更快,通常更好。你可以这样调用它:

[idx,C,sumd,D] = kmeans(A, k, 'Distance', 'cosine', 'Start', 'plus');

编辑:

这是第 3 部分所需的代码:

[~, min_idxs] = min(D, [], 1);
closest_vecs = A(min_idxs, :);

closest_vecs 的每一行 i 是最接近质心 i 的向量。