1. 程式人生 > >基礎演算法(二):Kmeans聚類演算法的基本原理與應用

基礎演算法(二):Kmeans聚類演算法的基本原理與應用

Kmeans聚類演算法的基本原理與應用


      內容說明:主要介紹Kmeans聚類演算法的數學原理,並使用matlab程式設計實現Kmeans的簡單應用,不對之處還望指正。

一、Kmeans數學原理

       以往的迴歸分類、樸素貝葉斯分類、SVM分類的樣本的標籤(類別)是已知的,通過大量的訓練樣本訓練得到模型,然後判斷新的樣本所屬已知類別中的哪一類。而Kmeans聚類屬於無監督學習,樣本所屬的類別是未知的,只是根據特徵將樣本分類,且類別空間也是根據需要人為選定的。

Kmeans核心思想:最小化所有樣本到所屬類別中心的歐式距離和,採用迭代的方式實現收斂。

      


      為了將J調整到最小,假設當前情況下J沒有達到最小,那麼可以通過固定每一個類別的中心u,調整每一個樣本的所屬類別c來減小J,也可以通過固定每一個樣本的所屬類別c,調整類別中心來減小J的值。理論上,可以有多組u,c值使得J最小,但實際應用中一般出現較少。

      J為非凸函式,所以最後收斂的點有可能是全域性最優,也有可能是區域性最優,說明Kmeans對初始條件比較敏感,可多次給定不同的初始條件計算J值,最後選擇最小的那一組作為最終的結果。下圖為不斷迭代至收斂的過程圖。

       

二、Kmeans聚類的matlab實現


      下面的程式碼主要來自參考資料,只是將三維資料改成二維資料,可以將二維訓練資料類比為學生的語文和數學的成績,通過聚類將300名學生按照成績分別ABC三類,三維資料對應著可以類比為學生的語數外成績。

      matlab程式碼實現:

kmeans_test.m

clear 
close all
clc
%% 採用隨機函式的方法產生訓練資料
%第一類資料
mu1=[0 0];                  %均值
S1=[0.3 0;0 0.35];          %協方差
data1=mvnrnd(mu1,S1,100);   %產生高斯分佈資料
%%第二類資料
mu2=[1.25 1.25];
S2=[0.3 0;0 0.35];
data2=mvnrnd(mu2,S2,100);
%第三個類資料
mu3=[1.25 -1.25];
S3=[0.3 0;0 0.35];
data3=mvnrnd(mu3,S3,100);

%% 顯示訓練資料
plot(data1(:,1),data1(:,2),'+');
hold on;
plot(data2(:,1),data2(:,2),'r+');
plot(data3(:,1),data3(:,2),'g+');
grid on;
%三類資料合成一個不帶標號的資料類
data=[data1;data2;data3];   %這裡的data是不帶標號的
%k-means聚類
[u re]=KMeans(data,3);  %最後產生帶標號的資料,標號在所有資料的最後,意思就是資料再加一維度
[m n]=size(re);
%% 最後顯示聚類後的資料
figure;
hold on;
for i=1:m 
    if re(i,3)==1   
         plot(re(i,1),re(i,2),'ro'); 
    elseif re(i,3)==2
         plot(re(i,1),re(i,2),'go'); 
    else 
         plot(re(i,1),re(i,2),'bo'); 
    end
end
plot(u(:,1),u(:,2),'k+'); 
grid on;
KMeans.m
%N是資料一共分多少類
%data是輸入的不帶分類標號的資料
%u是每一類的中心
%re是返回的帶分類標號的資料
function [u re]=KMeans(data,N)   
    [m n]=size(data);   %m是資料個數,n是資料維數
    ma=zeros(n);        %每一維最大的數
    mi=zeros(n);        %每一維最小的數
    u=zeros(N,n);       %隨機初始化,最終迭代到每一類的中心位置
    for i=1:n
       ma(i)=max(data(:,i));    %每一維最大的數
       mi(i)=min(data(:,i));    %每一維最小的數
       for j=1:N
            u(j,i)=ma(i)+(mi(i)-ma(i))*rand();  %隨機初始化,不過還是在每一維[min max]中初始化好些
       end      
    end
   
    while 1
        pre_u=u;            %上一次求得的中心位置
        for i=1:N
            tmp{i}=[];      % 公式一中的x(i)-uj,為公式一實現做準備
            for j=1:m
                tmp{i}=[tmp{i};data(j,:)-u(i,:)];
            end
        end
        
        quan=zeros(m,N);
        for i=1:m           %計算每一個樣本i所屬的類別
            c=[];
            for j=1:N
                c=[c norm(tmp{j}(i,:))];
            end
            [junk index]=min(c);
            quan(i,index)=norm(tmp{index}(i,:));           
        end
        
        for i=1:N            %更新類別變化後的類別中心位置
           for j=1:n
                u(i,j)=sum(quan(:,i).*data(:,j))/sum(quan(:,i));
           end           
        end
        
        if norm(pre_u-u)<0.1  %不斷迭代直到位置不再變化或變化極小
            break;
        end
    end
    
    re=[];
    for i=1:m
        tmp=[];
        for j=1:N
            tmp=[tmp norm(data(i,:)-u(j,:))];
        end
        [junk index]=min(tmp);
        re=[re;data(i,:) index];
    end
end
執行結果如下,這是按照高斯分佈產生的3*100個二維的訓練資料,可以根據需要替換訓練資料。


這是Kmeans聚類之後的資料,每種顏色對應著一個類別,中心的黑色十字叉為類別中心。

三、Kmeans演算法的實際應用

      Kmeans演算法的應用很多,後期會根據自己碰到的具體應用不斷更新。
      若有錯誤之處,還望不吝指出,謝謝。