K-means算法算是個著名的聚類算法了,不僅容易實現,並且效果也不錯,訓練過程不需人工干預,實乃模式識別等領域的居家必備良品啊,今天就拿這個算法練練手。屬於無監督學習中間接聚類方法中的動態聚類
流程:
1.隨機選取樣本中的K個點作爲聚類中心
2.計算所有樣本到各個聚類中心的距離,將每個樣本規劃在最近的聚類中
3.計算每個聚類中所有樣本的中心,並將新的中心代替原來的中心
4.檢查新老聚類中心的距離,如果距離超過規定的閾值,則重複2-4,直到小於閾值
聚類屬於無監督學習,以往的迴歸、樸素貝葉斯、SVM等都是有類別標籤y的,也就是說樣例中已經給出了樣例的分類。而聚類的樣本中卻沒有給定y,只有特徵x,比如假設宇宙中的星星可以表示成三維空間中的點集。聚類的目的是找到每個樣本x潛在的類別y,並將同類別y的樣本x放在一起。比如上面的星星,聚類後結果是一個個星團,星團裏面的點相互距離比較近,星團間的星星距離就比較遠了。
K-means算法是將樣本聚類成k個簇(cluster),具體算法描述如下:
1、 隨機選取k個聚類質心點(cluster centroids)爲。
2、 重複下面過程直到收斂 {
對於每一個樣例i,計算其應該屬於的類
對於每一個類j,重新計算該類的質心
K是我們事先給定的聚類數,代表樣例i與k個類中距離最近的那個類,的值是1到k中的一個。質心代表我們對屬於同一個類的樣本中心點的猜測,拿星團模型來解釋就是要將所有的星星聚成k個星團,首先隨機選取k個宇宙中的點(或者k個星星)作爲k個星團的質心,然後第一步對於每一個星星計算其到k個質心中每一個的距離,然後選取距離最近的那個星團作爲,這樣經過第一步每一個星星都有了所屬的星團;第二步對於每一個星團,重新計算它的質心(對裏面所有的星星座標求平均)。重複迭代第一步和第二步直到質心不變或者變化很小。
下圖展示了對n個樣本點進行K-means聚類的效果,這裏k取2。
參考;http://blog.csdn.net/holybin/article/details/22969747
Kmeans有以下幾個優點:
1、是解決聚類問題的一種經典算法,算法簡單、快速。
2、對處理大數據集,該算法是相對可伸縮的和高效率的,因爲它的複雜度是線性的,大約是O(nkt),其中n是所有樣本的數目,k是簇的數目,t是迭代的次數。通常k<<n。
3、該算法是收斂的(不會無限迭代下去)。
4、算法嘗試找出使平方誤差函數值最小的k個劃分。當簇是密集的、球狀或團狀的,而簇與簇之間區別明顯時,它的聚類效果很好。
Kmeans也存在如下缺點:
1、只有在簇的平均值被定義的情況下才能使用,不適用於某些應用,如涉及有分類屬性的數據不適用。它的前提假設是樣本數據的協方差矩陣已經歸一化。
2、雖然理論證明它是一定可以收斂的,但是不能保證是全局收斂,可能是局部收斂,這樣的話找到的聚類中心不一定是最佳方案。
3、要求用戶必須事先給出要生成的簇的數目K。對於同一個數據樣本集合,選擇不同的K值,得到的結果是不一樣的,甚至是不合理的。
4、對中心初值敏感,對於不同的初始值,可能會導致不同的聚類結果。
5、對於"噪聲"和孤立點數據敏感,少量的該類數據能夠對平均值產生極大影響。
6、不適合於發現非凸面形狀的簇,或者大小差別很大的簇。
CV_EXPORTS_W double kmeans( InputArray data, int K, InputOutputArray bestLabels,
TermCriteria criteria, int attempts,
int flags, OutputArray centers = noArray() );
注意,在opencv中,kmeans()函數是在core.h頭文件中的,所以首先要包含這個頭文件。下面分析其參數:
1 InputArray data:輸入的待聚類向量,其中每一行是一個樣本,有多少列,就有多少個樣本。
2 int K: 要聚類的個數。
3 InputOutputArray bestLabels:行數與data是一樣的,每行有一個數字,代表分類的編號。比如聚類的數目是8類,那麼每行的數字在0-3。
4 TerCriteria criteria:這個變量用於控制結束條件。其中TerCriteria是一個模板類,在opencv中的定義如下:
TermCriteria::TermCriteria(int _type, int _maxCount, double _epsilon)
: type(_type), maxCount(_maxCount), epsilon(_epsilon) {}
其中,type的類型有三種:
TermCriteria::COUNT: 代表以運行的步數爲結束條件。
TermCriteria::EPS: 代表迭代到閾值時結束。
TermCriteria::COUNT + TermCriteria::EPS:當步數或閾值中有一個達到條件時終止。
_maxCount是運行的步數,_epsilon是閾值。
5 int attempts:這個變量控制kmean算法進行的次數,選擇最優的結果做爲最後結果。
6 int flags:這個變量可以取以下三個類型。
KMEANS_RANDOM_CENTERS:隨機選擇初始中心。
KMEANS_PP_CENTERS:以一種算法,確定初始中心。
KMEANS_USE_INITIAL_LABELS:用戶自定義中心。
7 centers:這個變量代表具體的聚類中心。
下面來看一個例子
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/core/core.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( int /*argc*/, char** /*argv*/ )
{
const int MAX_CLUSTERS = 5;
Scalar colorTab[] =
{
Scalar(0, 0, 255),
Scalar(0,255,0),
Scalar(255,100,100),
Scalar(255,0,255),
Scalar(0,255,255)
};
Mat img(500, 500, CV_8UC3);
RNG rng(12345);
for(;;)
{
int k, clusterCount = rng.uniform(2, MAX_CLUSTERS+1);
int i, sampleCount = rng.uniform(1, 1001);
Mat points(sampleCount, 1, CV_32FC2), labels;
clusterCount = MIN(clusterCount, sampleCount);
Mat centers(clusterCount, 1, points.type());
/* generate random sample from multigaussian distribution */
for( k = 0; k < clusterCount; k++ )
{
Point center;
center.x = rng.uniform(0, img.cols);
center.y = rng.uniform(0, img.rows);
Mat pointChunk = points.rowRange(k*sampleCount/clusterCount,
k == clusterCount - 1 ? sampleCount :
(k+1)*sampleCount/clusterCount);
rng.fill(pointChunk, CV_RAND_NORMAL, Scalar(center.x, center.y), Scalar(img.cols*0.05, img.rows*0.05));
}
randShuffle(points, 1, &rng);
kmeans(points, clusterCount, labels,
TermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0),
3, KMEANS_PP_CENTERS, centers);
img = Scalar::all(0);
for( i = 0; i < sampleCount; i++ )
{
int clusterIdx = labels.at<int>(i);
Point ipt = points.at<Point2f>(i);
circle( img, ipt, 2, colorTab[clusterIdx], CV_FILLED, CV_AA );
}
imshow("clusters", img);
char key = (char)waitKey();
if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
break;
}
return 0;
}
matlab
K-means聚類算法採用的是將N*P的矩陣X劃分爲K個類,使得類內對象之間的距離最大,而類之間的距離最小。
使用方法:
Idx=Kmeans(X,K)
[Idx,C]=Kmeans(X,K)
[Idx,C,sumD]=Kmeans(X,K)
[Idx,C,sumD,D]=Kmeans(X,K)
[…]=Kmeans(…,’Param1’,Val1,’Param2’,Val2,…)
各輸入輸出參數介紹:
X N*P的數據矩陣
K 表示將X劃分爲幾類,爲整數
Idx N*1的向量,存儲的是每個點的聚類標號
C K*P的矩陣,存儲的是K個聚類質心位置
sumD 1*K的和向量,存儲的是類間所有點與該類質心點距離之和
D N*K的矩陣,存儲的是每個點與所有質心的距離
[…]=Kmeans(…,'Param1',Val1,'Param2',Val2,…)
這其中的參數Param1、Param2等,主要可以設置爲如下:
1. ‘Distance’(距離測度)
‘sqEuclidean’ 歐式距離(默認時,採用此距離方式)
‘cityblock’ 絕度誤差和,又稱:L1
‘cosine’ 針對向量
‘correlation’ 針對有時序關係的值
‘Hamming’ 只針對二進制數據
2. ‘Start’(初始質心位置選擇方法)
‘sample’ 從X中隨機選取K個質心點
‘uniform’ 根據X的分佈範圍均勻的隨機生成K個質心
‘cluster’ 初始聚類階段隨機選擇10%的X的子樣本(此方法初始使用’sample’方法)
matrix 提供一K*P的矩陣,作爲初始質心位置集合
3. ‘Replicates’(聚類重複次數) 整數
<span style="font-size:18px;">X = [randn(100,2)+ones(100,2);...
randn(100,2)-ones(100,2)];
opts = statset('Display','final');
[idx,ctrs] = kmeans(X,2,...
'Distance','city',...
'Replicates',5,...
'Options',opts);
plot(X(idx==1,1),X(idx==1,2),'r.','MarkerSize',12)
hold on
plot(X(idx==2,1),X(idx==2,2),'b.','MarkerSize',12)
plot(ctrs(:,1),ctrs(:,2),'kx',...
'MarkerSize',12,'LineWidth',2)
plot(ctrs(:,1),ctrs(:,2),'ko',...
'MarkerSize',12,'LineWidth',2)
legend('Cluster 1','Cluster 2','Centroids',...
'Location','NW')
</span>
圖像識別算法交流 QQ羣:145076161,歡迎圖像識別與圖像算法,共同學習與交流