ISODATA聚类分析算法原理与C++实现

本文介绍了ISODATA聚类算法的原理,包括其与Kmeans的区别,并详细阐述了ISODATA的基本步骤、关键步骤原理。此外,还提供了C++代码实现的结构和主要类的介绍,以及如何使用这段代码进行聚类分析。文章最后分析了聚类效果并给出了代码仓库链接。
摘要由CSDN通过智能技术生成


最近在填之前的坑,尝试用C++实现一个ISODATA的聚类分析算法,目前代码已经码完了,就慢慢的把文档给补上,记录一下自己零零碎碎做的工作;给自己立的flag画一个句号吧。

Kmeans聚类算法的原理

  • 在分析一些数据前,我们需要选取通过一些方式对数据的种类进行划分,“物以类聚,人以群分”,分类是为了进一步的分析数据的性质。
  • Kmeans聚类算法的一般步骤为
    1. 随机选取k个中心点
    2. 遍历所有样本,将数据划分到最近的中心点中(所谓近,即欧式距离近)
    3. 计算每个聚类的平均值,得到新的聚类中心
    4. 重复上述2-3步骤,直至所有中心点趋于收敛(变化幅度较小)或达到一定的迭代次数
  • kmeans的原理简单,应用也很多,但是k的选取很重要,如果没有数据的先验知识,可能需要多次尝试不同的k值进行迭代计算,观察效果。

ISODATA聚类算法的原理

  • 可以看作Kmeans的一种衍生,既然我们有时候只能大致确定k的范围,而不能确定k,那么可以加入分裂、合并机制,通过更自动化的机制,灵活的确定k的值

ISODATA算法的基本步骤

  1. 参数设置,需要设置的参数包括:

    • nc : 初始聚类中心个数
    • c : 预期的聚类个数
    • tn : 每一类中允许的样本最少数目(少于该数目的聚类可能会被删除)
    • te : 类内相对标准差上限(超过该上限的聚类,可能会被分裂)
    • tc : 聚类中心点之间的最小距离
    • nt : 每次迭代中最多可以合并的次数
    • ns : 最多迭代次数
  2. 初始化

    1. 在所有样本中,随机选取nc个不重复样本作为聚类中心,之后根据距离最小法判断所有样本属于哪一种聚类
    2. 对第一次初始化后的聚类,检测是否符合tn条件,样本数目小于tn的类别被取消,重新根据上一步的距离最小法进行分配
  3. 计算分类后的聚类参数,包含以下参数:

    • 聚类中心
    • 各类中样本到聚类中心的平均距离
    • 各个样本到其所属类别中心的总体平均距离
  4. 根据当前的状态选择下一步的行为,进行分裂、合并或停止

    1. 若迭代次数达到要求,则停止
    2. 若当前聚类数量小于期望数量的一般,则进行分裂检测,判断当前是否需要分裂,若需要则执行分裂行为
    3. 若聚类数量大于期望数量的两倍,则进行合并检测,判断是否需要合并,若需要则执行合并行为
    4. 若聚类数量在期望聚类数量的1/2到2倍之间,奇数次迭代则执行分裂检测,偶数次迭代则进行合并检测

关键步骤原理

  • 分裂检测步骤
    1. 计算各个类别中,各个样本到类别中心的标准差,标准差为一矢量,求出每一类内标准差向量中的最大分量
    2. 若标准差向量中的最大分量大于te,同时满足以下条件之一,则对该类别进行分裂
      • 聚类个数小于期望个数一半
      • 聚类内部平均距离大于总体平均距离且聚类样本数量大于tn两倍
    3. 分裂操作:
      1. 在类内标准差最大的维度上分裂聚类中心点
      2. 利用距离最小法将当前聚类的样本点分配到两个聚类中
      3. 更新平均距离等聚类参数
  • 合并检测步骤
    1. 计算聚类中心两两之间的距离,距离小于tc的聚类对,按照距离越小优先级越大的原则,进行合并
    2. 合并的总次数小于设定值,且一次迭代中,一个聚类只能被合并一次
    3. 更新聚类参数

代码实现

代码结构

  • Cluster.h/cpp : 聚类结构体
  • common.h.cpp : 公共函数,包含一些矢量的操作符重载,主要为了编程时候的便捷
  • isodata.h/cpp : isodata聚类分析算法类
  • error.h : 定义了一些出错的输出字符,为了简便,会做一些出错的检查,然后报出错误,用于提示,但是本身不会做额外错误处理

主要类实现

  • Cluster
//Cluster.h
//
// Created by Jeff on 2019/1/6 0006.
//
#ifndef ISODATA_CLUSTER_H
#define ISODATA_CLUSTER_H
#include <vector>
#include <unordered_set>
using namespace std;
struct Cluster{
   
    double innerMeanDis; // 类内平均距离
    vector<double> sigma; // 每个聚类的标准差
    static double allMeanDis; // 总体平均距离
    vector<double> center; // 聚类中心位置的
    unordered_set<unsigned> ids; // 从属于此聚类的样本的id,位于isodata的data中的
    Cluster():
        center{
   }, innerMeanDis(0), sigma(vector<double>{
   }){
   }
    explicit Cluster(vector<double> &c):
        center(c), innerMeanDis(0), sigma(vector<double>(c.size(), 0)) {
   }
    void add_point(int p_index);
    void clear_ids();
};
#endif //ISODATA_CLUSTER_H
//Cluster.cpp
#include "Cluster.h"
#include "common.h"
double Cluster::allMeanDis = 0;
/**
 * 向聚类中添加点
 * @param p_index 点的id
 */
void Cluster::add_point(int p_index) {
   
    if (ids.find(static_cast<const unsigned int &>(p_index)) != ids.end())
    {
   
        cout << WARN_POINT_REPEAT << endl;
        return;
    }
    ids.emplace(p_index);
}
/**
 * 清除聚类中的所有点
 */
void Cluster::clear_ids() {
   
    ids.clear();
}
  • ISODATA
//
// Created by Jeff on 2019/1/2 0002.
//
#ifndef ISODATA_ISODATA_H
#define ISODATA_ISODATA_H
#include <vector>
#include <iostream>
#include <string>
#include <algorithm>
#include <unordered_set>
#include <time.h>
#include <random>
#include "error.h"
#include "Cluster.h"
#include <deque>
#include <functional>
#include "common.h"
using namespace std;
// 实现ISODATA聚类算法
class isodata {
   
private:
    typedef function<vector<vector<double>>(void)> READFUNC;
    // 直接初始化的数据
    // 为了简单,不预留更改设置的接口,只在初始化时设置
    unsigned _c; // 预期的聚类个数
    unsigned _nc; // 初始聚类中心数目
    unsigned _tn; // 每一类中允许的样本最少数目
    double _te; // 类内相对标准差上限
    double _tc; // 聚类中心点之间的最小距离
    unsigned _nt; // 每次迭代中最多可以合并的次数
    unsigned _ns; // 最多迭代次数
    // 不直接在构造函数中初始化
    unsigned row; // 数据的行数,也就是样本个数
    unsigned col; // 数据的列数,也就是特征个数
    vector<vector<double>> data; // 待分类的数据
    deque<Cluster> clusters; // 聚类
    READFUNC read_func; // 读取数据的函数,可以自定义
    double alpha; // 分裂系数
public:
    /**
     * 构造函数
     * @param _c 预期的聚类个数
     * @param _nc 初始聚类中心数目
     * @param _tn 每一类中允许的样本最少数目
     * @param _te 类内相对标准差上限
     * @param _tc 聚类中心点之间的最小距离
     * @param _nt 每次迭代中最多可以合并的次数
     * @param _ns 最多迭代次数
     * @param func 读取数据的函数,无输入,返回二维double vector
     */
    explicit isodata(unsigned int c, unsigned int _nc, unsigned int _tn,
                     double _te, double _tc, unsigned int _nt,
                     unsigned int _ns, READFUNC func) :
                     _c(c), _nc(_nc), _tn(_tn),
                     _te(_te), _tc(_tc), _nt(_nt),
                     _ns(_ns), row(0), col(0),
                     clusters(), read_func(std::move(func)), alpha(0.3) {
   
    }
    void run()
    {
   
        setData();
        init_clusters();
        for (int i = 0; i < _ns; ++i) {
   
            re_assign();
            check_tn(<
  • 7
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
ISODATA聚类算法是一种在负荷曲线聚类领域中应用的算法,在Matlab中也有相应的实现。它是对经典的ISODATA聚类算法进行改进的,主要解决了K-means算法需要事先确定聚类数目的问题。ISODATA算法新增了合并和分裂这两个操作,并引入了很多参数。相比于K-means算法ISODATA算法的优点在于可以动态调整聚类数目,有效解决了事先无法确定聚类数目的问题。 具体而言,L-ISODATA聚类算法是将ISODATA算法应用在负荷曲线聚类领域中,并对ISODATA聚类算法进行了改进。该算法解决了随机选取初始聚类中心可能导致算法收敛较慢、效果较差的问题,同时还可以捕捉到负荷曲线中的高维特征。 如果你想了解更多关于ISODATA聚类算法在Matlab中的实现,可以参考相关的参考文献或者搜索相关的Matlab代码、数据、文章讲解。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【风光场景生成】基于改进ISODATA的负荷曲线聚类算法(Matlab代码实现)](https://blog.csdn.net/Ke_Yan_She/article/details/129634340)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值