模糊聚类算法(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

相关文章

Qt把文件夹从A移动到B的实现示例

《Qt把文件夹从A移动到B的实现示例》本文主要介绍了Qt把文件夹从A移动到B的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录如何移动一个文件? 如何移动文件夹(包含里面的全部内容):如何删除文件夹:QT 文件复制,移动(

Flask 验证码自动生成的实现示例

《Flask验证码自动生成的实现示例》本文主要介绍了Flask验证码自动生成的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 目录生成图片以及结果处理验证码蓝图html页面展示想必验证码大家都有所了解,但是可以自己定义图片验证码

VSCode配置Anaconda Python环境的实现

《VSCode配置AnacondaPython环境的实现》VisualStudioCode中可以使用Anaconda环境进行Python开发,本文主要介绍了VSCode配置AnacondaPytho... 目录前言一、安装 Visual Studio Code 和 Anaconda二、创建或激活 conda

使用mvn deploy命令上传jar包的实现

《使用mvndeploy命令上传jar包的实现》本文介绍了使用mvndeploy:deploy-file命令将本地仓库中的JAR包重新发布到Maven私服,文中通过示例代码介绍的非常详细,对大家的学... 目录一、背景二、环境三、配置nexus上传账号四、执行deploy命令上传包1. 首先需要把本地仓中要

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

MySQL中实现多表查询的操作方法(配sql+实操图+案例巩固 通俗易懂版)

《MySQL中实现多表查询的操作方法(配sql+实操图+案例巩固通俗易懂版)》本文主要讲解了MySQL中的多表查询,包括子查询、笛卡尔积、自连接、多表查询的实现方法以及多列子查询等,通过实际例子和操... 目录复合查询1. 回顾查询基本操作group by 分组having1. 显示部门号为10的部门名,员

java导出pdf文件的详细实现方法

《java导出pdf文件的详细实现方法》:本文主要介绍java导出pdf文件的详细实现方法,包括制作模板、获取中文字体文件、实现后端服务以及前端发起请求并生成下载链接,需要的朋友可以参考下... 目录使用注意点包含内容1、制作pdf模板2、获取pdf导出中文需要的文件3、实现4、前端发起请求并生成下载链接使

Java逻辑运算符之&&、|| 与&、 |的区别及应用

《Java逻辑运算符之&&、||与&、|的区别及应用》:本文主要介绍Java逻辑运算符之&&、||与&、|的区别及应用的相关资料,分别是&&、||与&、|,并探讨了它们在不同应用场景中... 目录前言一、基本概念与运算符介绍二、短路与与非短路与:&& 与 & 的区别1. &&:短路与(AND)2. &:非短

Java的volatile和sychronized底层实现原理解析

《Java的volatile和sychronized底层实现原理解析》文章详细介绍了Java中的synchronized和volatile关键字的底层实现原理,包括字节码层面、JVM层面的实现细节,以... 目录1. 概览2. Synchronized2.1 字节码层面2.2 JVM层面2.2.1 ente

Linux下修改hostname的三种实现方式

《Linux下修改hostname的三种实现方式》:本文主要介绍Linux下修改hostname的三种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下修改ho编程stname三种方式方法1:修改配置文件方法2:hFvEWEostnamectl命