K-means代码

K-means的源码实现
一般情况下,我们通过C++/Matlab/Python等语言进行实现K-means算法,结合近期我刚刚学的C++,先从C++实现谈起,C++里面我们一般采用的是OpenCV库中写好的K-means函数,即cvKmeans2,首先来看函数原型:
从OpenCV manual看到的是:
int cvKMeans2(const CvArr* samples, int nclusters,
CvArr* labels, CvTermCriteria termcrit,
int attempts=1, CvRNG* rng=0,int flags=0,
CvArr* centers=0,double* compactness=0);
由于除去已经确定的参数,我们自己需要输入的为:
void cvKMeans2(
const CvArr* samples, //输入样本的浮点矩阵,每个样本一行。
int cluster_count,//所给定的聚类数目
* labels,//输出整数向量:每个样本对应的类别标识
CvTermCriteria termcrit //指定聚类的最大迭代次数和/或精度(两次迭代引起的聚类中心的移动距离)
);
其使用例程为:

1 #ifdef _CH_
2 #pragma package
3 #endif
4
5 #define CV_NO_BACKWARD_COMPATIBILITY
6
7 #ifndef _EiC
8 #include "cv.h"
9 #include "highgui.h"
10 #include
11 #endif
12
13 int main( int argc, char** argv )
14 {
15#define MAX_CLUSTERS 5//设置类别的颜色,个数(《=5)
16CvScalar color_tab[MAX_CLUSTERS];
17IplImage* img = cvCreateImage( cvSize( 500, 500 ), 8, 3 );
18CvRNG rng = cvRNG(-1);
19CvPoint ipt;
20
21color_tab[0] = CV_RGB(255,0,0);
22color_tab[1] = CV_RGB(0,255,0);
23color_tab[2] = CV_RGB(100,100,255);
24color_tab[3] = CV_RGB(255,0,255);
25color_tab[4] = CV_RGB(255,255,0);
26
27cvNamedWindow( "clusters", 1 );
28
29for(; ; )
30{
31char key;
32int k, cluster_count = cvRandInt(&rng)%MAX_CLUSTERS + 1;
33int i, sample_count = cvRandInt(&rng)%1000 + 1;
34CvMat* points = cvCreateMat( sample_count, 1, CV_32FC2 );
35CvMat* clusters = cvCreateMat( sample_count, 1, CV_32SC1 );
36cluster_count = MIN(cluster_count, sample_count);
37
38/** generate random sample from multigaussian distribution */
39for( k = 0; k < cluster_count; k++ )
40{
41CvPoint center;
42CvMat point_chunk;
43center.x = cvRandInt(&rng)%img->width;
44center.y = cvRandInt(&rng)%img->height;
45cvGetRows( points, &point_chunk, k*sample_count/cluster_count,
46k == cluster_count - 1 ? sample_count :
47(k+1)*sample_count/cluster_count, 1 );
48
49cvRandArr( &rng, &point_chunk, CV_RAND_NORMAL,
50cvScalar(center.x,center.y,0,0),
51cvScalar(img->width*0.1,img->height*0.1,0,0));
52}
53
54/** shuffle samples */
55for( i = 0; i < sample_count/2; i++ )
56{
57CvPoint2D32f* pt1 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count;
58CvPoint2D32f* pt2 = (CvPoint2D32f*)points->data.fl + cvRandInt(&rng)%sample_count;
59CvPoint2D32f temp;
60CV_SWAP( *pt1, *pt2, temp );
61}
62
63printf( "iterations=%d\n", cvKMeans2( points, cluster_count, clusters,
64cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 1.0 ),
655, 0, 0, 0, 0 ));
66
67cvZero( img );
68
69for( i = 0; i < sample_count; i++ )
70{
71int cluster_idx = clusters->data.i[i];
72ipt.x = (int)points->data.fl[i*2];
73ipt.y = (int)points->data.fl[i*2+1];
74cvCircle( img, ipt, 2, color_tab[cluster_idx], CV_FILLED, CV_AA, 0 );
75}
76
77cvReleaseMat( &points );
78cvReleaseMat( &clusters );
79
80cvShowImage( "clusters", img );
81
82key = (char) cvWaitKey(0);
83if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
84break;
85}
86
87cvDestroyWindow( "clusters" );
88return 0;
89 }
90
91 #ifdef _EiC
92 main(1,"kmeans.c");
93 #endif

至于cvKmeans2函数的具体实现细节,可参见OpenCV源码
下面是Python的实现代码(网上所找):
1#!/usr/bin/python
2
3 from __future__ import with_statement
4 import cPickle as pickle
5 from matplotlib import pyplot
6 from numpy import zeros, array, tile
7 from scipy.linalg import norm
8 import numpy.matlib as ml
9 import random
10
11 def kmeans(X, k, observer=None, threshold=1e-15, maxiter=300):
12N = len(X)
13labels = zeros(N, dtype=int)
14centers = array(random.sample(X, k))
15iter = 0
16
17def calc_J():
18sum = 0
19for i in xrange(N):
20sum += norm(X[i]-centers[labels[i]])
21return sum
22
23def distmat(X, Y):
24n = len(X)
25m = len(Y)
26xx = ml.sum(X*X, axis=1)
27yy = ml.sum(Y*Y, axis=1)
28xy = ml.dot(X, Y.T)
29
30return tile(xx, (m, 1)).T+tile(yy, (n, 1)) - 2*xy
31
32Jprev = calc_J()
33while True:
34# notify the observer
35if observer is not None:
36observer(iter, labels, centers)
37
38# calculate distance from x to each center
39# distance_matrix is only available in scipy newer than 0.7
40# dist = distance_matrix(X, centers)
41dist = distmat(X, centers)
42# assign x to nearst center
43labels = dist.argmin(axis=1)
44# re-calculate each center
45for j in range(k):
46idx_j = (labels == j).nonzero()
47centers[j] = X[idx_j].mean(axis=0)
48
49J = calc_J()
50iter += 1
51
52if Jprev-J < threshold:
53break
54Jprev = J
55if iter >= maxiter:
56break
57
58# final notification
59if observer is not None:
60observer(iter, labels, centers)
61
62 if __name__ == '__main__':
63# load previously generated points
64with open('cluster.pkl') as inf:
65samples = pickle.load(inf)
66N = 0
67for smp in samples:
68N += len(smp[0])
69X = zeros((N, 2))
70idxfrm = 0
71for i in range(len(samples)):
72idxto = idxfrm + len(samples[i][0])
73X[idxfrm:idxto, 0] = samples[i][0]
74X[idxfrm:idxto, 1] = samples[i][1]
75idxfrm = idxto
76
77def observer(iter, labels, centers):
78print "iter %d." % iter
79colors = array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
80pyplot.plot(hold=False)# clear previous plot
81pyplot.hold(True)
82
83# draw points
84data_colors=[colors[lbl] for lbl in labels]
85pyplot.scatter(X[:, 0], X[:, 1], c=data_colors, alpha=0.5)
86# draw centers
87pyplot.scatter(centers[:, 0], centers[:, 1], s=200, c=colors)
88
89pyplot.savefig('kmeans/iter_%02d.png' % iter, format='png')
90
91kmeans(X, 3, observer=observer)

【K-means代码】matlab的kmeans实现代码可直接参照其kmeans(X,k)函数的实现源码。

    推荐阅读