模糊聚类算法(FCM)和硬聚类算法(HCM)的VB6.0实现及其应用

2024-01-29 12:32

本文主要是介绍模糊聚类算法(FCM)和硬聚类算法(HCM)的VB6.0实现及其应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

程序实现:

    上面的公式看似复杂,其实我们关心的就是最后的5个计算步骤,这里说明一下,有的书上以隶属度矩阵的某一范数小于一定值作为收敛的条件,这也可,不过计算量稍微要大一点了。

        程序采用VB6.0编制,完全按照以上的步骤进行。

    

'程序实现功能:模糊聚类和硬聚类
'作    者: laviewpbt
'联系方式:
laviewpbt@sina.com
'QQ:33184777
'版本:Version 2.3.1
'说明:复制请保留源作者信息,转载请说明,欢迎大家提出意见和建议


Private Declare Function GetTickCount Lib "kernel32" () As Long

Private Enum IniCenterMethod    '初始中心的方法
    CreateRandom                '随机的中心点
    CreateByHcm                 '由HCM创建的中心点
    CreateByRandomZadeh         '先随机创建隶属矩阵,然后计算得到的中心点

    CreateByHand                '手工确定初始中心点

End Enum


Private Enum AntiFuzzyMethod    '反模糊的方法
    Max                         '最大隶属度法
    Middle                      '中位数法
    Mean                        '加权均值法
End Enum


Private Type FcmInfo
     Center() As Double         '聚类中心
     Degree() As Double         '隶属度,为Double类型
     Class() As Byte            '记录数据属于那一类
     TimeUse As Long            '所用时间
     Iterations  As Long        '迭带次数
     ErrMsg As String           '错误信息
End Type


Private Type HcmInfo
    Center() As Double          '聚类中心
    Class() As Byte             '记录数据属于那一类
    TimeUse As Long             '所用时间
    Iterations  As Long         '迭带次数
    ErrMsg As String            '错误信息
End Type

'*************************************************************************************
'*    作    者 :    laviewpbt
'*    函 数 名 :    Fcm
'*    参    数 :    Data     -   待分类的样本,第一维的大小表示样本的个数,
'*                                第二维的大小表示样本的维数
'*                   Cluster  -   分类数
'*                   CreateIniCenter - 初始聚类中心的创建方法
'*                   AntiFuzzy -  反模糊化的方法
'*                   Exponent  -  一个控制聚类效果的参数,一般取2
'*                   Maxiterations  - 最大的迭代次数
'*                   MinImprovement - 最小的改进参数(两次迭代间聚类中心的距离)
'*    返回值 :      FcmInfo结构,记录了相关的参数
'*    功能描述 :    利用模糊理论的聚类方法把数据分类
'*    日    期 :    2004-10-27 10.25.32
'*    修 改 人 :    laviewpbt
'*    日    期 :    2006-11-7 19.25.31
'*    版    本 :    Version 2.3.1
'**************************************************************************************



Private Function Fcm(ByRef Data() As Double, ByVal Cluster As Long, Optional ByVal CreateIniCenter As IniCenterMethod = IniCenterMethod.CreateByHcm, Optional AntiFuzzy As AntiFuzzyMethod = Max, Optional Exponent As Byte = 2, Optional Maxiterations As Long = 400, Optional MinImprovement As Double = 0.01, Optional ByRef CenterByHandle As Variant) As FcmInfo
    If ArrayRange(Data) <> 2 Then
        Fcm.ErrMsg = "数据只能为二维数组"
        Exit Function
    End If
    Dim i As Long, j As Long, k As Long, l As Long, m As Long
    Dim DataNumber As Long, DataSize As Long
    Dim Temp As Double, Sum1 As Double, Sum2 As Double, Sum3 As Double, Index As Integer
    Dim OldCenter() As Double
    Fcm.TimeUse = GetTickCount
    DataNumber = UBound(Data, 1): DataSize = UBound(Data, 2)
    ReDim Fcm.center(1 To Cluster, 1 To DataSize) As Double
    ReDim Fcm.Degree(1 To Cluster, 1 To DataNumber) As Double
    ReDim Fcm.Class(1 To DataNumber) As Byte
    ReDim OldCenter(1 To Cluster, 1 To DataSize) As Double
    On Error GoTo ErrHandle:
    Randomize
    If CreateIniCenter = CreateRandom Then
        For i = 1 To Cluster
            For j = 1 To DataSize
                OldCenter(i, j) = Data(Rnd * DataNumber, j)    '产生随机初始中心点
            Next
        Next
    ElseIf CreateIniCenter = CreateByHcm Then
        Dim HcmCenter As HcmInfo
        HcmCenter = Hcm(Data, Cluster)
        For i = 1 To Cluster
            For j = 1 To DataSize
                OldCenter(i, j) = HcmCenter.center(i, j)   '产生HCM初始中心点
            Next
        Next
    ElseIf CreateIniCenter = CreateByRandomZadeh Then
        ReDim RndDegree(1 To Cluster, 1 To DataNumber) As Double
        Dim RndSum As Double
        For i = 1 To Cluster
            For j = 1 To DataNumber
                RndDegree(i, j) = Rnd           '创建随机的隶属度
            Next
        Next
        For j = 1 To DataNumber
            RndSum = 0
            For i = 1 To Cluster
                RndSum = RndSum + RndDegree(i, j)
            Next
            For i = 1 To Cluster
                RndDegree(i, j) = RndDegree(i, j) / RndSum   '隶属度矩阵每列之后必须为1
            Next
        Next
       
        For i = 1 To Cluster
            For j = 1 To DataSize
                Sum1 = 0: Sum2 = 0
                For k = 1 To DataNumber
                    Temp = Exp(Log(RndDegree(i, k)) * Exponent)  '其实就是RndDegree(i, k)^Exponent
                    Sum1 = Sum1 + Temp * Data(k, j)           '隶属度的平方乘以数值
                    Sum2 = Sum2 + Temp                        '隶属度的和
                Next
                OldCenter(i, j) = Sum1 / Sum2                 '得到聚类中心
            Next
        Next
    ElseIf CreateIniCenter = CreateByHand Then
        If IsMissing(CenterByHandle) Then
            Fcm.ErrMsg = "请提供初始聚类中心。."
            Exit Function
        ElseIf UBound(CenterByHandle, 1) <> Cluster Or UBound(CenterByHandle, 2) <> DataSize Then
            Fcm.ErrMsg = "手工提供的初始聚类中心维数有错误."
            Exit Function
        End If
        For i = 1 To Cluster
            For j = 1 To DataSize
                OldCenter(i, j) = CenterByHandle(i, j)
            Next
        Next
    End If

    
    Do
        Fcm.Iterations = Fcm.Iterations + 1
        For i = 1 To Cluster
            For j = 1 To DataNumber
                Sum1 = 0: Sum3 = 1
                For k = 1 To DataSize
                    Temp = Data(j, k) - OldCenter(i, k)
                    Sum1 = Sum1 + Temp * Temp             '计算第j点到第i个聚类中心的距离
                Next
                If Sum1 = 0 Then
                    Fcm.Degree(i, j) = 1                      '如果j点与第i个聚类中心重合,则完全属于该类
                Else
                    For k = 1 To Cluster
                        Sum2 = 0
                        If k <> i Then
                            For l = 1 To DataSize
                                Temp = Data(j, l) - OldCenter(k, l)
                                Sum2 = Sum2 + Temp * Temp  '计算第j点到其他聚类中心的距离
                            Next
                            Sum3 = Sum3 + Exp(Log(Sum1 / Sum2) * (2 / (Exponent - 1)))      '计算累加值,
                        End If
                    Next
                    Fcm.Degree(i, j) = 1 / Sum3    '计算新的隶属度
                End If
            Next
        Next
       
        For i = 1 To Cluster
            For j = 1 To DataSize
                Sum1 = 0: Sum2 = 0
                For k = 1 To DataNumber
                    Temp = Exp(Log(Fcm.Degree(i, k)) * Exponent)
                    Sum1 = Sum1 + Temp * Data(k, j)           '隶属度的平方乘以数值
                    Sum2 = Sum2 + Temp                        '隶属度的和
                Next
                Fcm.Center(i, j) = Sum1 / Sum2                    '得到新的聚类中心
            Next
        Next
       
        Temp = 0
        For i = 1 To Cluster
            For j = 1 To DataSize
                Temp = Temp + (OldCenter(i, j) - Fcm.Center(i, j)) ^ 2      ' 计算两次迭代之间的聚类中心的距离
                OldCenter(i, j) = Fcm.Center(i, j)                          ' 保留上一次的聚类中心
            Next
        Next

    Loop While Fcm.Iterations < Maxiterations And Temp > MinImprovement
   
    If AntiFuzzy = Max Then
        For i = 1 To DataNumber
            Temp = -1
            For k = 1 To Cluster
                If Temp < Fcm.Degree(k, i) Then    '得到列方向的最大值
                    Temp = Fcm.Degree(k, i)
                    Index = k
                End If
            Next
            Fcm.Class(i) = Index                  'Index记录了列方向最大隶属度的类
        Next
    ElseIf AntiFuzzy = Mean Then
         For i = 1 To DataNumber
             Temp = 0
             For j = 1 To Cluster
                Temp = Temp + Fcm.Degree(j, i) * j   '去隶书乘以对应的类别数之和
             Next
             Fcm.Class(i) = CInt(Temp)
      Next
    ElseIf AntiFuzzy = Middle Then
        For i = 1 To DataNumber
            Temp = 0
            For j = 1 To Cluster
                If Temp <= 0.5 And Temp + Fcm.Degree(j, i) >= 0.5 Then
                    Index = j
                    Exit For
                Else
                    Temp = Temp + Fcm.Degree(j, i)   '取面积的一半处
                End If
            Next
            Fcm.Class(i) = Index
        Next
    End If
    Fcm.TimeUse = GetTickCount - Fcm.TimeUse
    Exit Function
ErrHandle:
    Fcm.ErrMsg = Err.Description
    Fcm.TimeUse = GetTickCount - Fcm.TimeUse
End Function


'*************************************************************************************
'*    作    者 :    laviewpbt
'*    函 数 名 :    Hcm
'*    参    数 :    Data     -   待分类的样本,第一维的大小表示样本的个数,
'*                                第二维的大小表示样本的维数
'*                   Cluster  -   分类数
'*                   Maxiterations  - 最大的迭代次数
'                    MinImprovement - 最小的改进参数(两次迭代间聚类中心的距离)
'*    返回值 :      HcmInfo结构,记录了相关的参数
'*    功能描述 :    直接利用硬聚类方法把数据分类
'*    日    期 :    2004-10-24 20.10.56
'*    修 改 人 :    laviewpbt
'*    日    期 :    2006-11-7 20.11.23
'*    版    本 :    Version 2.3.1
'**************************************************************************************


Private Function Hcm(ByRef Data() As Double, ByVal Cluster As Byte, Optional Maxiterations As Long = 400, Optional MinImprovement As Double = 0.01) As HcmInfo
    If ArrayRange(Data) <> 2 Then
        Hcm.ErrMsg = "数据只能为二维数组"
        Exit Function
    End If
    Dim i As Long, j As Long, k As Long, l As Long, m As Long
    Dim DataNumber As Long, DataSize As Long
    Dim Temp As Double, DX As Double, DY As Double, SumValue() As Double, SumNumber() As Long
    Dim OldCenter() As Double, Distance As Double, Dist As Double, Index As Long
    On Error GoTo ErrHandle:
    Hcm.TimeUse = GetTickCount
    DataNumber = UBound(Data, 1): DataSize = UBound(Data, 2)
    ReDim Hcm.Center(1 To Cluster, 1 To DataSize) As Double
    ReDim Hcm.Class(1 To DataNumber) As Byte
    ReDim OldCenter(1 To Cluster, 1 To DataSize) As Double
    For i = 1 To Cluster
        For j = 1 To DataSize
            OldCenter(i, j) = Data(i * DataNumber / Cluster, j) '产生初始中心点
        Next
    Next
    Do
        Hcm.Iterations = Hcm.Iterations + 1
        ReDim SumNumber(Cluster) As Long
        ReDim SumValue(Cluster, DataSize) As Double
        For i = 1 To DataNumber
            Distance = 40000000000#
            For j = 1 To Cluster
                Dist = 0
                For k = 1 To DataSize
                    Temp = Data(i, k) - OldCenter(j, k)
                    Dist = Dist + Temp * Temp             '计算第j点到第i个聚类中心的距离
                Next
                If Distance > Dist Then
                    Distance = Dist
                    Index = j                         '把i点归于距离该点最近的中心点所在的类
                End If
            Next
            Hcm.Class(i) = Index
            For j = 1 To DataSize
                SumValue(Index, j) = SumValue(Index, j) + Data(i, j)
            Next
            SumNumber(Index) = SumNumber(Index) + 1
        Next
       
        For i = 1 To Cluster
            For k = 1 To DataSize
                If SumNumber(i) = 0 Then
                    Hcm.Center(i, k) = Data(Rnd * DataNumber, k)
                Else
                    Hcm.Center(i, k) = SumValue(i, k) / SumNumber(i)         '求新的中心
                End If
            Next
        Next
        Temp = 0
        For i = 1 To Cluster
            For j = 1 To DataSize
                Temp = Temp + (OldCenter(i, j) - Hcm.Center(i, j)) ^ 2      ' 计算两次迭代之间的聚类中心的距离
                OldCenter(i, j) = Hcm.Center(i, j)                          ' 保留上一次的聚类中心
            Next
        Next
    Loop While Hcm.Iterations < Maxiterations And Temp > MinImprovement
    Hcm.TimeUse = GetTickCount - Hcm.TimeUse
    Exit Function
ErrHandle:
    Hcm.ErrMsg = Err.Description
    Hcm.TimeUse = GetTickCount - Hcm.TimeUse
    End Function

 

'*************************************************************************************
'*    作    者 :    网络
'*    函 数 名 :    ArrayRange
'*    参    数 :    Data     -   待测试的数据
'*    返回值 :      返回数组的维数
'*    日    期 :    2006-7-10 13.20.40
'*    修 改 人 :    laviewpbt
'*    日    期 :    2006-11-7 10。10。45
'*    版    本 :    Version 1.2.1
'**************************************************************************************
Public Function ArrayRange(Data() As Double) As Integer
    Dim i As Integer, ret As Integer
    Dim ErrF As Boolean
    ErrF = False
    On Error GoTo ErrHandle
    For i = 1 To 60               'VB中数组最大为60
        ret = UBound(mArray, i)   '用UBound函数判断某一维的上界,如果大数组的实际维数时产生超出范围错误,此时我们通过Resume Next 来捕捉错这个错误
        ret = ret + 1
        If ErrF Then Exit For
    Next
    ArrayRange = ret
    Exit Function
ErrHandle:
    ret = i
    ErrF = True
    Resume Next
End Function

 

 

 

 测试情况:

1、简单数据的聚类

原始数据为:
1    2   
2    3   
1.5    2.5   
1.5    2   
5.1    1   
4.1    1   
5    3   
6    2   
聚类中心为:
1.500    2.374   
5.062    1.750   
隶属矩阵为:
1.00 1.00 1.00 1.00 0.00 0.03 0.02 0.00
0.00 0.00 0.00 0.00 1.00 0.97 0.98 1.00

这篇关于模糊聚类算法(FCM)和硬聚类算法(HCM)的VB6.0实现及其应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/656908

相关文章

nginx -t、nginx -s stop 和 nginx -s reload 命令的详细解析(结合应用场景)

《nginx-t、nginx-sstop和nginx-sreload命令的详细解析(结合应用场景)》本文解析Nginx的-t、-sstop、-sreload命令,分别用于配置语法检... 以下是关于 nginx -t、nginx -s stop 和 nginx -s reload 命令的详细解析,结合实际应

Linux下删除乱码文件和目录的实现方式

《Linux下删除乱码文件和目录的实现方式》:本文主要介绍Linux下删除乱码文件和目录的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下删除乱码文件和目录方法1方法2总结Linux下删除乱码文件和目录方法1使用ls -i命令找到文件或目录

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

mybatis执行insert返回id实现详解

《mybatis执行insert返回id实现详解》MyBatis插入操作默认返回受影响行数,需通过useGeneratedKeys+keyProperty或selectKey获取主键ID,确保主键为自... 目录 两种方式获取自增 ID:1. ​​useGeneratedKeys+keyProperty(推

Spring Boot集成Druid实现数据源管理与监控的详细步骤

《SpringBoot集成Druid实现数据源管理与监控的详细步骤》本文介绍如何在SpringBoot项目中集成Druid数据库连接池,包括环境搭建、Maven依赖配置、SpringBoot配置文件... 目录1. 引言1.1 环境准备1.2 Druid介绍2. 配置Druid连接池3. 查看Druid监控

Linux在线解压jar包的实现方式

《Linux在线解压jar包的实现方式》:本文主要介绍Linux在线解压jar包的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux在线解压jar包解压 jar包的步骤总结Linux在线解压jar包在 Centos 中解压 jar 包可以使用 u

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构

基于Python实现一个图片拆分工具

《基于Python实现一个图片拆分工具》这篇文章主要为大家详细介绍了如何基于Python实现一个图片拆分工具,可以根据需要的行数和列数进行拆分,感兴趣的小伙伴可以跟随小编一起学习一下... 简单介绍先自己选择输入的图片,默认是输出到项目文件夹中,可以自己选择其他的文件夹,选择需要拆分的行数和列数,可以通过

Python中将嵌套列表扁平化的多种实现方法

《Python中将嵌套列表扁平化的多种实现方法》在Python编程中,我们常常会遇到需要将嵌套列表(即列表中包含列表)转换为一个一维的扁平列表的需求,本文将给大家介绍了多种实现这一目标的方法,需要的朋... 目录python中将嵌套列表扁平化的方法技术背景实现步骤1. 使用嵌套列表推导式2. 使用itert