k-means算法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
k-means算法
k-means算法是无监督学习领域最为经典的算法之一。
接触聚类算法,首先需要了解k-means算法的实现原理和步骤。
本文将对k-means算法的基本原理和实现实例进行分析。
希望对喜欢机器学习的童鞋们,有一定的帮助和启发。
首先看看wiki上对k-means算法的基本阐述。
k-means clustering is a method of vector
quantization, originally from signal
processing, that is popular for cluster
analysis in data mining. k-means clustering
aims to partition n observations into k
clusters in which each observation belongs to
the cluster with the nearest mean, serving as
a prototype of the cluster.
可以看出,k-means算法就是将 n 个数据点进行聚类分析,得到 k 个聚类,使得每个数据点到聚类中心的距离最小。
而实际上,这个问题往往是NP-hard的,以此有许多启发式的方法求解,从而避开局部最小值。
值得注意的是,k-means算法往往容易和k-nearest neighbor classifier(k-NN)算法混淆。
后者是有监督学习的分类(回归)算法,主要是用来判定数据点属于哪个类别中心的。
A simple example for k-means clustering
k-means算法有很多应用:
•图像分割(Image Segmentation)
•基因分割数据聚类分析(Clustering Gene
Segementation Data)
•新闻聚类分析(News Article Clustering)
•语言聚类分析(Clustering Languages)
•物种分析(Species Clustering)
•异常检测(Anomaly Detection)
•\cdots
数学描述
给定数据集 X=\{x^{(1)},x^{(2)},\cdots,x^{(n)}\} ,其中每个数据样本 x^{(i)}\in \mathbb{R}^d . k-mean算法旨在将 n 个数据点划分为 k(k\leq n) 个聚类集合
\bm{S}=\{S_1,S_2,\cdots,S_k\} ,使得每个聚类集合中的样本点与聚类中心的距离平方和最小(WCSS, within-cluster sum of squares),i.e. 方差最小。
形式上,目标函数为:
\arg\min_\bm{S}\sum_{i=1}^{k}\sum_{\bm{x}\in
S_i}\left||\bm{x}-\bm{\mu_i} |
\right|^2=\arg\min_\bm{S}\sum_{i=1}^{k}|S_i|\text{Var} S_i.
其中 \bm{\mu}_i 是集合 S_i 中心点,也就是聚类中心。
上式也等价于最小化簇内节点的成对平方偏差,即
\arg\min_\bm{S}\sum_{i=1}^k\frac{1}{2|S_i|}\sum_{\bm{x },\bm{y}\in S_i}\left||\bm{x}-\bm{y}|\right|^2.
上式可以被简化为:
\sum_{\bm{x}\in S_i}\left||\bm{x}-
\bm{\mu}_i|\right|^2=\sum_{\bm{x}\neq \bm{y}\in
S_i}(\bm{x}-\bm{\mu}_i)(\bm{\mu}_i-\bm{y}).
由于总方差是定值,因此最小化簇内成对节点平方偏差和(WCSS)等价于最大化簇间成对节点平方偏差和(BCSS, between-cluster sum of squares).
算法描述
初始化 k 个聚类中心
m_1^{(1)},m_2^{(1)},\cdots,m_k^{(1)} ,算法通过交替运行如下两个步骤: Assignments step:将每个数据点分配到其与聚类中心具有最小平方欧氏距离的聚类集合中,这直观上叫做“最近邻聚类中心”。
即 S_i^{(t)}=\left\{ x_p:\left\| x_p-m_i^{(t)} \right\|^2\leq \left\| x_p-m_j^{(t)}
\right\| ^2 \, \forall \,j,\, 1\leq j\leq k \right \},
其中每个 x_p 恰好只被分配给一个 S^{(t)} ,即使可能存在多个相等的最近邻聚类中心。
Update step:计算节点分配有聚类集合的新的样本中心,即
m_i^{(t+1)}=\frac{1}{\left|S_i^{(t)}\right|}\sum_{x_j\ in S_{i}^{(t)}}x_j.
算法的收敛条件是:聚类中心不再变化,或者达到一定的迭代次数。
这种算法不能保证收敛到全局最优。
在选取初始聚类中心数目时,可以采取常用的方法,即测试
10个不同的聚类中心,然后绘制K与误差平方和的曲线图,
找到曲线的拐点,即是合适的K值。
We run the algorithm for different values of
K(say K = 10 to 1) and plot the K values
against SSE(Sum of Squared Errors). And select
the value of K for the elbow point as shown in
the figure.
利用python编写k-means算法,数据样本点数3000,维度为2,如图所示:
数据样本点分布
随机初始化3个聚类中心点,如图中绿色五角星所示
k=3时,最终的聚类结果
图(a)表示k=6时的聚类结果,图(b)表示k=5的
聚类结果,图(c)表示k=4的聚类结果。
很显然,
当初始化聚类中心k的数目选取不当时,聚类的结果
比较差。
python代码如下:
fromcopyimportdeepcopyimportnumpyasnpimportpandasaspdf rommatplotlibimportpyplotaspltplt.rcParams['figure.fig size']=(16,9)#e('ggplot')# Importing the datasetdata=pd.read_csv('xclara.csv')print("Input Data and Shape")print(data.shape)data.head()# Getting the values and plotting
itf1=data['V1'].valuesf2=data['V2'].valuesX=np.array(l ist(zip(f1,f2)))fig1=plt.figure('fig1')plt.scatter(f1, f2,c='black',s=7)fig1.show()# Euclidean Distance Caculatordefdist(a,b,ax=1):returnnp.linalg.norm(a-
b,axis=ax)# Number of clustersk=3# X coordinates of random centroidsC_x=np.random.randint(0,np.max(X)-
20,size=k)# Y coordinates of random
centroidsC_y=np.random.randint(0,np.max(X)-
20,size=k)C=np.array(list(zip(C_x,C_y)),dtype=np.float 32)print("Initial Centroids")print(C)# Plotting along with the
Centroidsfig2=plt.figure('fig2')plt.scatter(f1,f2,c='' ,s=7)plt.scatter(C_x,C_y,marker='*',s=200,c='g')fig2.s how()# To store the value of centroids when it updatesC_old=np.zeros(C.shape)# Cluster Lables(0, 1, 2)clusters=np.zeros(len(X))# Error func. - Distance between new centroids and old
centroidserror=dist(C,C_old,None)# Loop will run till the error bees zerowhileerror!=0:# Assigning each value to its closest
clusterforiinrange(len(X)):distances=dist(X[i],C)clust er=np.argmin(distances)clusters[i]=cluster# Storing the old centroid valuesC_old=deepcopy(C)# Finding the new centroids by taking the average
valueforiinrange(k):points=[X[j]forjinrange(len(X))ifc lusters[j]==i]C[i]=np.mean(points,axis=0)error=dist(C, C_old,None)colors=['r','g','b','y','c','m']fig,ax=plt. subplots()foriinrange(k):points=np.array([X[j]forjinra nge(len(X))ifclusters[j]==i])ax.scatter(points[:,0],po ints[:,1],s=7,c=colors[i])ax.scatter(C[:,0],C[:,1],mar ker='*',s=200,c='')plt.show()
当采用scikit-learn库运行k-means算法时,采用3D绘图的方式,产生数据集采用make_blobs函数。
代码如下:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
plt.rcParams['figure.figsize'] = (16, 9)
# Creating a sample dataset with 4 clusters
X, y = make_blobs(n_samples=800, n_features=3,
centers=4)
fig1 = plt.figure('fig1')
ax = Axes3D(fig1)
ax.scatter(X[:, 0], X[:, 1], X[:, 2])
fig1.show()
# Initializing KMeans
kmeans = KMeans(n_clusters=4)
# Fitting with inputs
kmeans = kmeans.fit(X)
# Predicting the clusters
labels = kmeans.predict(X)
# Getting the cluster centers
C = kmeans.cluster_centers_
fig2 = plt.figure('fig2')
ax = Axes3D(fig2)
ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=y)
ax.scatter(C[:, 0], C[:, 1], C[:, 2], marker='*', c='', s=500)
fig2.show()
plt.show()
绘制出的聚类图像为:
数据点在3维空间的分布
采用scikit-learn库中提供的K-means算法进行聚
类分析后的结果图
K-means算法针对球形数据具有较好的聚类效果,另外,K-means算法对输入参数k的选取非常敏感,并且选取的初始聚类中心点不一致,得到的聚类结果有时相差很大。
相关的K-means算法介绍细节与实现可以参考:。