模糊ISODATA聚类分析算法与K-means算法

1、模糊ISODATA聚类分析算法

1.1、起源

在以往的算法中,判断一个事物是否属于某一类别,只有两种可能值:属于或者不属于,因此采用二值逻辑来表示即可。但实际生活中,自然语言中的很多概念都具有模糊性,事物往往不是严格地归属于某一类,而是以一定的隶属度属于某一类,因此诞生了模糊逻辑。

模糊逻辑:在模糊逻辑中,一个命题不再非真即假,它可以被认为是“部分的真”。模糊逻辑中的隶属度在[0,1]之间取值,用以表示程度。

1.2、概念

ISODATA算法是在k-均值算法的基础上,增加对聚类结果的“合并”和“分裂”两个操作,并设定算法运行控制参数的一种聚类算法。迭代次数会影响最终结果,迭代参数选择很重要。

模糊ISODATA聚类算法又称Fuzzy C-means算法,即模糊C均值聚类

1.3、方法

求出适当的模糊分类矩阵及聚类中心矩阵V,使目标函数

在这里插入图片描述
取得极小值。符号含义如下:
n:数据集大小。
c:类别数量。
rik:第k个对象属于第i类的程度。
q:参数。
uk:第k个对象。
Vi:第i类对应的聚类中心向量。
V:聚类中心矩阵,以Vi作为行所构成的矩阵。

1.4、算法步骤:

  1. 选定分类数c(2<=c<=n),取一初始模糊聚类矩阵,逐步迭代。
  2. 对于已得到的模糊聚类矩阵,计算聚类中心向量:

在这里插入图片描述
其中,在这里插入图片描述

  1. 更新模糊聚类矩阵,取

在这里插入图片描述

  1. 比较原来的模糊聚类矩阵和更新后的模糊聚类矩阵,其相减的绝对值若满足小于取定的精度(>0),则更新后的模糊分类矩阵和聚类中心矩阵即为所求,停止迭代;否则回到步骤二,重复进行。

1.5、实例

1.5.1、数据

  • 纹理数据集:Texture data set
  • 数据集简介:该数据集中的目的是区分11种不同的纹理(草皮,压制小牛皮,手工纸,拉菲亚编织成高绒头的棉布,棉帆布等),每种图案(像素)具有40种属性,通过估计四个方向上的四阶修改矩:0、45、90和135度。该数据集共有5500条数据。
  • 数据集维度:通过对0、45、90、135度四个方向的四阶修正矩估计,分别构建40个属性。只考虑当前像素、第一邻域和第二邻域之间的相关性。
  • 最终可分为11种纹理:
class lable class
2 Grass lawn (D09)
3 Pressed calf leather (D24)
4 Handmade paper (D57)
6 Raffia looped to a high pile: (D84)
7 Cotton canvas (D77)
8 Pigskin (D92)
9 Beach sand: (D28)
10 Beach sand (D29)
12 Oriental straw cloth (D53)
13 Oriental straw cloth (D78)
14 Oriental grass fiber cloth (D79)

1.5.2、实现

模糊ISODATA聚类代码如下:

clear;clc;%清除控制台数据

%1
%1.1 通过load()函数进行dat数据集的导入
%导入后的数据矩阵应为texture,但由于最后一个属性为class,将其舍去,得到一个新的数据矩阵data
load C:\Users\Desktop\texture.dat;%dat数据集存放的路径
for i=1:5500
    for j=1:40
        data(i,j)=texture(i,j);
        j=j+1;
    end;
    i=i+1;
end;
data = data';%一般数据每一行代表一个样本

%1.2 初始化重要参数
cluster_n = 11;%由于已知类别数为11,故将其赋值为11
iter = 70;%迭代次数上限为70次
q = 2;%参数
e=0.00001;%精度
num_data = size(data,1);%样本个数,该实例为5500
num_d = size(data,2);%样本维度,该实例为40

%1.3 初始化隶属度U,条件是每一列和为1
U = rand(cluster_n,num_data);
col_sum = sum(U);
U = U./col_sum(ones(cluster_n,1),:);

%
for i = 1:iter

    %2 更新聚类中心矩阵V
    for j = 1:cluster_n
        u_ij_m = U(j,:).^q;
        sum_u_ij = sum(u_ij_m);
        sum_1d = u_ij_m./sum_u_ij; 
        V(j,:) = u_ij_m*data./sum_u_ij;
    end
    
    %-计算目标函数J
    temp1 = zeros(cluster_n,num_data);
    for j = 1:cluster_n
        for k = 1:num_data
            temp1(j,k) = U(j,k)^q*(norm(data(k,:)-V(j,:)))^2;
        end
    end
    J(i) = sum(sum(temp1));
    U1=U;%利用U1,可判断是否停止迭代
    
    %3 更新隶属度矩阵U
    for j = 1:cluster_n
        for k = 1:num_data
            sum1 = 0;
            for j1 = 1:cluster_n
                temp = (norm(data(k,:)-V(j,:))/norm(data(k,:)-V(j1,:))).^(2/(q-1));
                sum1 = sum1 + temp;
            end
            U1(j,k) = 1./sum1;
        end
    end
    
    %4 比较原来的模糊聚类矩阵和更新后的模糊聚类矩阵,其相减的绝对值若满足小于取定的精度
    if cluster_n~=1 && max(abs(U1(j,k)-U(j,k)))<=e
       number=i;%记录迭代次数
       break;
    end
    U=U1;
    
end
U=U1;
figure;
subplot(1,2,1);
plot(J);%输出目标函数的变化
[~,label] = max(U); %利用最佳模糊分类聚类,找到所属的类
subplot(1,2,2);
gscatter(data(:,1),data(:,2),label)%画散点图

运行结果:

在这里插入图片描述
图片的左半部分绘制的是目标函数J,横坐标为迭代次数,纵坐标为目标函数J的取值。可观察出其变化趋势:目标函数J一开始迭代时,其取值大幅度下降,接着下降的幅度微弱,最后目标函数J的取值范围落在(400,450)之间。

图片的右半部分绘制的是类别,横坐标为数据集data的第一列,纵坐标为数据集data的第二列。

计算平均模糊熵:

classF=0;%记录平均模糊熵
for i=1:cluster_n
    for j=1:num_data
        classF=classF+U(i,j)*log(U(i,j));
    end
    classF=classF/num_data;
end
disp('迭代次数:');
disp(number);
disp('目标函数J:');
disp(J(number));
disp('平均模糊熵:');
disp(classF);

运行结果:
在这里插入图片描述
此次聚类共迭代38次,最终的目标函数J取446.1528。平均模糊熵用于检验聚类效果,越接近于0,聚类效果越好。此处平均模糊熵为-0.1577,属于一个较低的数值,说明聚类效果不错。

1.5.3、 参数改变

根据上面的代码,改变某些特定的参数,重复运行程序,可得下面两个表格:

(1)、当e=0.0001时,q改变:

q 2 3 4 5
迭代次数 38 19 32 54
目标函数J 446.1528 54.8826 5.2404 443.6537
平均模糊熵 -0.1577 -0.2120 -0.1212 -0.0939

(2)、当q=2时,e改变:

e 0.001 0.0001 0.00001 0.000001
迭代次数 2 43 38 16
目标函数J 1.1361e+03 389.3219 446.1528 0.4895
平均模糊熵 -0.2313 -0.1407 -0.1577 -0.2078

除了q=2、e=0.001时的情况(目标函数J为左上到右下的直线,明显错误),其他情况的目标函数J的变化趋势一致,但最终的取值有差别。
当e保持不变时,在一定范围内,随着q的增大,目标函数J的最终取值减小;超出范围,则q的增大也带动着目标函数J的最终取值的增长。
当q保持不变时,e取0.0001较为合适。

2、K-means算法

在之前的博客中,已经对K-means算法有所介绍(点此进入此前博客)。因此,这处直接进入实现阶段(所用数据同上)。

2.1 实现

导入数据并调用K-means算法:

clear;clc;%清除控制台数据

%1
%通过load()函数进行dat数据集的导入
%导入后的数据矩阵应为texture,但由于最后一个属性为class,将其舍去,得到一个新的数据矩阵data
load C:\Users\Desktop\texture.dat;
for i=1:5500
    for j=1:40
        data(i,j)=texture(i,j);
        j=j+1;
    end;
    i=i+1;
end;

output=k_means(data, 11);
data2=tabulate(output);%画出各个类有几个
subplot(1,2,1);
plot(data2(:,1),data2(:,2),'*');
subplot(1,2,2);
plot(output,'.');

K-means算法

%实现K-means算法的聚类功能

%输入:data--为一个M×N阶矩阵 ,表示样本集,其中M:样本数,N:样本维度数;
%    k_value:聚类的类别数
function [ output ] = k_means(data, k_value)% 输出:output, 是一个列向量 M×1,表示每一个样本属于的类别编号;

%从样本中,随机选取K个样本作为初始的聚类中心;
data_num = size(data, 1);
temp = randperm(data_num, k_value)';     
center = data(temp, :);

%用于计数迭代次数:
iteration = 0;
while 1

    %获得样本集与聚类中心的距离;
    distance = euclidean_distance(data, center);
    
    %将距离矩阵的每一行从小到大排序, 获得相应的index值,其实我们只需要index的第一列的值;
    [~, index] = sort(distance, 2, 'ascend');
    
    %接下来形成新的聚类中心;
    center_new = zeros(k_value, size(data, 2));
    for i = 1:k_value
        data_for_one_class = data(index(:, 1) == i, :);          
        center_new(i,:) = mean(data_for_one_class, 1);    %因为初始的聚类中心为样本集中的元素,所以不会出现某类别的样本个数为0的情况;
    end
    
    %输出迭代次数,给眼睛一个反馈;
    iteration = iteration + 1;
    fprintf('进行迭代次数为:%d\n', iteration);
    
    % 如果这两次的聚类中心不变,则停止迭代,跳出循环;
    if center_new == center
        break;
    end
    center = center_new;
    
end

output = index(:, 1);
end

计算距离的euclidean_distance函数:

%用于计算训练样本与聚类中心的的欧氏距离的平方;
function [ output ] = euclidean_distance(data, center)
%输入:data  为一个M×N阶矩阵 ,表示样本集,其中M:样本数,N:样本维度数;
%      centre 为一个K×N阶矩阵 ,表示K个聚类中心,其中N:样本维度数;
%      output 为一个M×K阶矩阵,第x行y列表示第X个样本与第Y个聚类中心的距离(每一行表示一个样本与K个聚类中心的距离)

data_num = size(data, 1);
center_num = size(center, 1);
output = zeros(data_num, center_num);

for i = 1:center_num
    difference = data - repmat(center(i,:), data_num, 1);%求样本集与第i个聚类中心的差;
    sum_of_squares = sum(difference .* difference, 2); %求平方,并对每一行求和;
    output(:, i) = sum_of_squares;             
end

end

运行结果1:
在这里插入图片描述在这里插入图片描述
运行结果2:
在这里插入图片描述在这里插入图片描述
运行结果3:
在这里插入图片描述
在这里插入图片描述
运行结果4:
在这里插入图片描述
在这里插入图片描述
运行结果5:
在这里插入图片描述
在这里插入图片描述

除了这五种运行结果外,还有很多种。准确来说,虽然数据一样,但每次运行后的聚类情况都不同(很少两个运行结果一模一样)。

在得到上面的五种运行结果过程中,也经历了一直处于迭代状态(上百次不等),但始终没有一个结果。发现:当运行k-means算法时,若在迭代30次内无法出现结果,则可进行重新初始化聚类中心。

在这五种运行结果中,除了运行结果3与运行结果5的聚类分布有曲线趋势大致相同,其他均无;而不同类别的个数分布更是相差甚远。

3、评价

  1. 模糊ISODATA聚类分析算法先进行计算隶属度,再通过某些方法(例如利用最佳模糊分类聚类)进行分类。而k-means算法从一开始谈论的就是属于或不属于。
  2. 模糊ISODATA聚类分析算法一般需要迭代30~60次,而适用的k-means算法(即不包括陷入死循环)在迭代10次之间可出现结果。
  3. 聚类中心矩阵的初始值很重要,特别是k-means算法。不合适的初始值会令k-means算法陷入死循环。
  4. 这两种方法对于同一个数据集,每次的运行结果都不同。
  5. 考虑综合情况,根据该实例分析,模糊ISODATA聚类分析算法中参数q最适宜的取值为3,精度e最适宜的取值为0.0001。

4、参考资料

(1)详解FCM算法原理及应用
(2) k-means算法及matlab实现
(3)一些用于聚类和分类问题的数据集

发布了13 篇原创文章 · 获赞 6 · 访问量 2293

猜你喜欢

转载自blog.csdn.net/weixin_44060222/article/details/102783565