Kmeans聚类算法(用于魔方机器人的色片分类及应用拓展)

K-means聚类是一种广泛使用的无监督学习算法,用于将数据点分成 K个聚类。它的主要目标是最小化每个聚类内数据点到聚类中心的距离之和,从而使得每个聚类内的数据点相似性最大,而不同聚类之间的差异性最大。

目录

1. K-means聚类的基本步骤

1.1 选择K个初始中心点

1.2 将每个数据点分配给最近的聚类中心

1.3 计算每个聚类的新中心

1.4 检查是否收敛

2. K-means算法的数学表述

3. K-means聚类的优点

4. K-means聚类的缺点

5. K-means的应用

6. K-means在魔方机器人的实际应用

6.1. 初始化:

6.2. 聚类过程:

6.3. 更新聚类中心:

6.4. 重复上述过程:

7. K-means在魔方机器人的详细代码解释


1. K-means聚类的基本步骤

K-means聚类算法的执行过程通常包括以下几个步骤:

1.1 选择K个初始中心点

首先,选择 KKK 个数据点作为初始聚类中心。这些中心可以随机选择,也可以使用某种启发式方法确定。

1.2 将每个数据点分配给最近的聚类中心

对于每个数据点,计算其到每个聚类中心的欧几里得距离(或其他距离度量),然后将该数据点分配给距离最近的聚类。

1.3 计算每个聚类的新中心

一旦所有数据点都被分配到某个聚类中,重新计算每个聚类的中心。新中心是聚类内所有数据点的平均值。

1.4 检查是否收敛

检查聚类中心是否发生变化。如果聚类中心不再发生变化,或者变化量小于某个阈值,算法收敛并终止。否则,返回步骤1.2,继续迭代。

2. K-means算法的数学表述

K-means算法的目标是最小化以下目标函数:

j=\sum_{i=1}^{k}\sum_{Xj\in Ci}^{}\left \| Xj-\mu i \right \|^2

其中:

  • K是聚类的数量。
  • Ci​ 表示第 i个聚类。
  • xj​ 表示属于聚类 Ci​ 的第 j 个数据点。
  • μi​ 是聚类 Ci​ 的中心。
  • ∥⋅∥表示欧几里得距离。

目标函数 J 的含义是在所有聚类中最小化数据点到各自聚类中心的距离平方和。

3. K-means聚类的优点

  • 简单易懂:K-means算法简单易于实现,计算速度快。
  • 高效:对于大数据集,K-means算法的计算效率较高。
  • 可伸缩性:K-means可以扩展到较大的数据集。

4. K-means聚类的缺点

  • 对初始值敏感:K-means的结果依赖于初始聚类中心的选择,可能会陷入局部最优解。
  • 需要指定K值:在使用K-means算法时,需要预先指定聚类的数量 KKK,这对于未知数据的聚类来说可能比较困难。
  • 只适用于球形聚类:K-means假设每个聚类是球形的,这使得它在处理复杂形状的聚类时效果不佳。

5. K-means的应用

K-means聚类广泛应用于各种领域,如图像分割、客户分群、模式识别、市场营销等。在这些领域中,K-means可以帮助识别数据的内在结构,从而进行进一步的分析或决策。

6. K-means在魔方机器人的实际应用

K-means聚类是一种常见的无监督学习算法,旨在将数据点分成K个聚类。以下是K-means聚类在魔方机器人中如何实现的详细解释:

6.1. 初始化:


   代码首先将所有点的分类索引设为-1。
   使用魔方数据的最后6个点(第48到53列)作为初始聚类中心。

6.2. 聚类过程:


   逐次进行9轮,每轮为每一类选择一个点:
       对于每一个未分类的点,计算其到当前聚类中心的欧几里得距离。
       将距离当前聚类中心最近的点归类到该聚类。

6.3. 更新聚类中心:


      如果`CenterMove`为真,则重新计算每个聚类的中心:
      计算新中心时,使用逐次平均法,即新的中心是当前中心与新加入点的平均值。

6.4. 重复上述过程:


     重复选择最近点和更新聚类中心的步骤,直到所有点都被分配到某个聚类。

这个过程正是K-means聚类的核心思想,即通过不断迭代更新聚类中心和分配点,使得每个点到其所属聚类中心的距离最小化。

7. K-means在魔方机器人的详细代码解释

这段代码实现了一个聚类算法,旨在为魔方的色片进行分类,详细代码如下:

Cube CenterGrab(Cube cube, bool CenterMove)
{
    // 清空Idx数组,将所有点的分类索引设为-1
    for (int i = 0; i < 54; i++)
    {
        cube.Idx[i] = -1;
    }

    // 初始化聚类中心
    int Center[3][6];
    for (int i = 0; i < 6; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            // 将CubeData的第48到53列作为初始聚类中心
            Center[j][i] = cube.CubeData[j][48 + i];
        }
    }

    // 逐次抢占9个点,每次为每一类选择一个点
    for (int i = 0; i < 9; i++)
    {
        for (int c = 0; c < 6; c++)
        {
            int minDis = 1000000; // 初始化最小距离为一个很大的数
            int p = -1; // 初始化点索引为-1

            // 遍历所有点,找到距离当前聚类中心最近的点
            for (int j = 0; j < 54; j++)
            {
                if (cube.Idx[j] == -1) // 只考虑尚未分类的点
                {
                    int dis = 0; // 计算距离
                    for (int k = 0; k < 3; k++)
                    {
                        dis += (cube.CubeData[k][j] - Center[k][c]) * (cube.CubeData[k][j] - Center[k][c]);
                    }
                    if (dis < minDis)
                    {
                        minDis = dis;
                        p = j; // 更新最近点的索引
                    }
                }
            }
            cube.Idx[p] = c; // 将最近点归类到当前类别
        }

        // 重新调整聚类中心
        if (CenterMove)
        {
            int count[6] = { 0, 0, 0, 0, 0, 0 }; // 每类点的计数器
            for (int i = 0; i < 54; i++)
            {
                int Class = cube.Idx[i]; // 获取点所属的类
                if (Class != -1)
                {
                    count[Class]++; // 更新类别计数
                    for (int j = 0; j < 3; j++)
                    {
                        // 计算新的聚类中心,逐次平均法
                        Center[j][Class] = (Center[j][Class] * (count[Class] - 1) + cube.CubeData[j][i]) / count[Class];
                    }
                }
            }
        }
    }
    return cube; // 返回更新后的魔方
}

代码解释和注释

1. 清空`Idx`数组:
    清空Idx数组,将所有点的分类索引设为-1
    for (int i = 0; i < 54; i++)
    {
        cube.Idx[i] = -1;
    }
   将`Idx`数组中的所有值初始化为-1,表示所有的点尚未被分类。

2. 初始化聚类中心:
    初始化聚类中心
    int Center[3][6];
    for (int i = 0; i < 6; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            // 将CubeData的第48到53列作为初始聚类中心
            Center[j][i] = cube.CubeData[j][48 + i];
        }
    }
    `Center`数组用来存储每个类的中心点。
    初始化时将`cube.CubeData`的第48到53列作为初始聚类中心。

3. 逐次抢占9个点:
    逐次抢占9个点,每次为每一类选择一个点
    for (int i = 0; i < 9; i++)
    {
        for (int c = 0; c < 6; c++)
        {
            int minDis = 1000000; // 初始化最小距离为一个很大的数
            int p = -1; // 初始化点索引为-1

            // 遍历所有点,找到距离当前聚类中心最近的点
            for (int j = 0; j < 54; j++)
            {
                if (cube.Idx[j] == -1) // 只考虑尚未分类的点
                {
                    int dis = 0; // 计算距离
                    for (int k = 0; k < 3; k++)
                    {
                        dis += (cube.CubeData[k][j] - Center[k][c]) * (cube.CubeData[k][j] - Center[k][c]);
                    }
                    if (dis < minDis)
                    {
                        minDis = dis;
                        p = j; // 更新最近点的索引
                    }
                }
            }
            cube.Idx[p] = c; // 将最近点归类到当前类别
        }

        // 重新调整聚类中心
        if (CenterMove)
        {
            int count[6] = { 0, 0, 0, 0, 0, 0 }; // 每类点的计数器
            for (int i = 0; i < 54; i++)
            {
                int Class = cube.Idx[i]; // 获取点所属的类
                if (Class != -1)
                {
                    count[Class]++; // 更新类别计数
                    for (int j = 0; j < 3; j++)
                    {
                        // 计算新的聚类中心,逐次平均法
                        Center[j][Class] = (Center[j][Class] * (count[Class] - 1) + cube.CubeData[j][i]) / count[Class];
                    }
                }
            }
        }
    }
    外层循环抢占9个点,每次为每一类选择一个点。
    内层循环遍历所有点,找到距离当前聚类中心最近的未分类点。
    将最近的点归类到当前类别。
    若`CenterMove`为真,则重新调整聚类中心,采用逐次平均法更新中心点位置。

这个算法使用了一种类似于K-means的聚类方法,将魔方上的色片分成6类,并且在每次迭代后根据新的分类中心重新计算中心位置。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我也想知道why

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值