經典演算法之k means聚類

2021-07-09 01:11:39 字數 3342 閱讀 5205

原理

給定一系列樣本點,想要分成k類

(1)首先從中隨機選取k個點作為質心

(2)分別計算每個點到這k個質心的歐式距離(為例),到哪個質心距離最小,這個點就屬於這個質心,這樣把所有點分成k類

(3)再分別計算k類中每一類新的質心,根據公式2

(4)迭代(2)(3),直到達到最優條件,條件如最小距離平方和公式3;

公式1公式2

公式3

close all;

clc;

%第一類資料

mu1=[0 0 0]; %均值

s1=[0.3 0 0;0 0.35 0;0 0 0.3]; %協方差

data1=mvnrnd(mu1,s1,100); %產生高斯分布資料

%%第二類資料

mu2=[1.25 1.25 1.25];

s2=[0.3 0 0;0 0.35 0;0 0 0.3];

data2=mvnrnd(mu2,s2,100);

%第三個類資料

mu3=[-1.25 1.25 -1.25];

s3=[0.3 0 0;0 0.35 0;0 0 0.3];

data3=mvnrnd(mu3,s3,100);

%顯示資料

plot3(data1(:,1),data1(:,2),data1(:,3),'+');

hold on;

plot3(data2(:,1),data2(:,2),data2(:,3),'r+');

plot3(data3(:,1),data3(:,2),data3(:,3),'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,4)==1

plot3(re(i,1),re(i,2),re(i,3),'ro');

elseif re(i,4)==2

plot3(re(i,1),re(i,2),re(i,3),'go');

else

plot3(re(i,1),re(i,2),re(i,3),'bo');

endendgrid 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

endwhile 1

pre_u=u; %上一次求得的中心位置

for i=1:n

tmp=; % 公式一中的x(i)-uj,為公式一實現做準備

for j=1:m

tmp=[tmp;data(j,:)-u(i,:)];

endend

quan=zeros(m,n);

for i=1:m %公式一的實現

c=;for j=1:n

c=[c norm(tmp(i,:))];

end[junk index]=min(c);

quan(i,index)=norm(tmp(i,:));

endfor i=1:n %公式二的實現

for j=1:n

u(i,j)=sum(quan(:,i).*data(:,j))/sum(quan(:,i));

end

endif norm(pre_u-u)<0.1 %不斷迭代直到位置不再變化

break;

endend

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];

endend

c++實現

#include #include #include #include #include #include #define k 3//簇的數目

using namespace std;

//存放元組的屬性資訊

typedef vectortuple;//儲存每條資料記錄

int datanum;//資料集中資料記錄數目

int dimnum;//每條記錄的維數

//計算兩個元組間的歐幾裡距離

double getdistxy(const tuple& t1, const tuple& t2)

return sqrt(sum);

}//根據質心,決定當前元組屬於哪個簇

int clusteroftuple(tuple means,const tuple& tuple)

} //cout<

} for(int j=1; j<=dimnum; ++j)

t[j] /= num;

return t;

//cout<

tuples.push_back(tuple);

} cout<

聚類演算法之Kmeans

kmeans是聚類演算法中比較簡單的演算法,也用的非常多。這裡進行簡單的解釋,主要目的在於給自己記錄,以備以後檢視。k均值聚類的主要思想是為了使得各個類的點離聚類中心都盡可能近。k均值聚類的演算法可以描述為 輸入 資料集d d 聚類簇個數 k 演算法 從資料集d中隨機選擇k個樣本作為初始聚類中心 r...

聚類演算法之K means

k means演算法也稱k 均值聚類演算法。它試圖通過基於原型的 劃分的距離計算來發現k個使用者預先指定的簇。將一組資料劃分為預先設定好的k個簇,也可理解為隨機選擇k個向量作為初始均值向量。接下來根據均值向量將樣本劃分到距離最近的均值向量所在的簇中。這是一次迭代過程。重新計算並更新均值向量,不斷重複...

聚類演算法之K Means演算法

對大量未進行標註 unsupervised learning 的資料集,並按照資料集本身的內部資料特徵將資料劃分為多個不同的類別,從而使得類別內的資料相似度高,而類別間的資料差異性較大。因此,它的重點就在於計算樣本間的相似度 similarity 輸入演算法所需資料,資料樣本集d 將樣本資料集分開的...