您的位置:首页 > 编程语言 > Python开发

Python机器学习——K-Means聚类

2017-09-14 23:03 99 查看
  样本集D={x⃗ 1,x⃗ 2,...,x⃗ N},假设聚类的簇划分C={C1,C2,...,CK}。k均值算法的目标是最小化平方误差:err=∑k=1K∑x⃗ i∈Ck||x⃗ i−μk→||22  其中,μ⃗ k=1Ck∑x⃗ i∈Ckx⃗ i是簇Ck的均值向量。上式刻画了簇类样本围绕簇均值向量的紧密程度,err越小,则簇内样本簇均值向量越紧密。

  现在要求最优化问题:minC∑k=1K∑x⃗ i∈Ck||x⃗ i−μk→||22  该问题的求解需要考察样本集合D的所有可能的簇划分。k均值算法采用贪心算法,通过迭代优化来近似求解。其原理为:k均值算法首先假设一组向量作为所有簇的簇均值限量,然后根据假设的簇均值向量给出了数据集D的一个簇划分,再根据这个簇划分来计算真实的簇均值向量。

如果真实的簇均值向量等于假设的簇均值向量,则说明假设正确。根据假设簇均值向量给出的数据集D的一个簇划分确实是元问题的解。

如果真实的簇均值向量等不于假设的簇均值向量,则可以将真实的簇均值向量作为新的假设簇均值向量,继续求解。

  这里的一个关键就是:给定假设簇均值向量,如何计算出数据集D的一个簇划分?k均值算法的策略是:样本距离哪个簇的簇均值向量最近,则该样本就划归到那个簇。

  下面给出k均值算法:

输入

样本集D={x⃗ 1,x⃗ 2,...,x⃗ N}

聚类簇数K

输出:簇划分C={C1,C2,...,CK}

算法步骤

从数据集D中随机选取K个样本作为初始均值向量{μ⃗ 1,μ⃗ 2,...,μ⃗ K}

重复迭代直到算法收敛,迭代内容如下:

初始化阶段:取Ck=∅,k=1,2,...,K

划分阶段:令i=1,2,...,N

计算x⃗ i的簇标记如下:λi=argmink||x⃗ i−μ⃗ k||2,k∈1,2,...,K

然后将样本x⃗ i划入相应的簇:Cλi=Cλi⋃(x⃗ i)

重计算阶段:计算μ⃗ ′′kμ⃗ ”k=1|Ck|∑x⃗ i∈Ckx⃗ i

终止条件判断:

如果对所有的k∈1,2,…,K,都有μ⃗ ∗k=μ⃗ k,则算法收敛,终止迭代

否则重赋值μ⃗ k=μ⃗ ∗k

Python实战

  KMeans是scikit-learn提供的聚类算法模型,其原型为:

class sklearn.cluster.KMeans(n_clusters=8, init=’k-means++’, n_init=10, max_iter=300, tol=0.0001, precompute_distances=’auto’, verbose=0, random_state=None, copy_x=True,n_jobs=1,algorithm=’auto’)


参数

n_clusters:一个整数,指定分类簇的数量

init:一个字符串,指定初始均值向量的策略。可以为如下:

K-Means++:该初始化策略选择的初始均值向量相互之间距离都较远,它的效果较好

random:从数据集中随机选取K个样本作为初始均值向量

或者提供一个数组,数组的形状为(n_clusters.n_features),该数组作为初始均值向量
k均值算法总能够收敛,但是其收敛情况高度依赖于初始化的向量。有可能收敛于局部极小值。因此通常都是用多组初始向量来计算若干次,选择其中最优的一次。而k-means++策略选择的初始均值向量可以在一定程度上解决这个问题。


n_init:一个整数,指定了k均值算法运行的次数。每一次都会选择一组不同的初始化均值向量,最终算法会选择最佳的分类簇作为最终的结果。

max_iter:一个整数,指定了单轮k均值算法中,最大的迭代次数。算法总的最大迭代次数为max_iter * n_init。

precompute_distance:可以为布尔值或字符串’auto’。该参数指定是否提前计算好样本之间的距离(如果提前计算距离,则需要更多的内存,但是算法会运行的更快)。

auto:如果n_samples * n_clusters > 12 million,则不提前计算

True:总是提前计算

False :总是不提前计算

tol:一个浮点数,指定了算法收敛的阈值

n_jobs:一个正数,指定任务并行时的CPU数量。如果为-1则使用所有可用的CPU

verbose:一个整数,如果为0,则不输出日志信息;如果为1,则每隔一段时间打印一次日志信息;如果大于1,则打印日志信息更频繁

random_state:一个整数或一个RandomState实例,,或者为None

如果为整数,则它指定了随机数生成器的种子

如果为RandomState实例,则它指定了随机数生成器

如果为None,则使用默认的随机数生成器

copy_x:布尔值,主要用于precompute_distance=True的情况

如果为True,则预计算距离的时候,并不修改原始数据

如果为False,则预计算距离的时候,会修改原数数据用于节省内存,但后当算法结束的时候,会将原数据返回。但是可能会因为浮点数的表示,会有一些精度误差

属性

cluster_centers_:给出分类簇的均值向量

labels_:给出了每个样本所属的簇的标记

inertia_:给出了每个样本距离它最近的簇中心的距离之和

方法

fit(X[,y]):训练模型

fitpredict(X[,y]):训练模型并预测每个样本所属的簇,它等价于先调用fit方法,后调用predict方法

predict:预测样本所属的簇

score(X[,y]):给出了样本距离一个簇中心的偏移量的相反数。

#-*-coding:gbk-*-
'''
Created on 2017年9月15日

@author:
'''
from sklearn import cluster
from sklearn.metrics import adjusted_rand_score
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets.samples_generator import make_blobs
from matplotlib.pyplot import plot

"""
产生数据
"""
def create_data(centers,num=100,std=0.7):
X,labels_true = make_blobs(n_samples=num,centers=centers, cluster_std=std)
return X,labels_true

"""
数据作图
"""
def plot_data(*data):
X,labels_true=data
labels=np.unique(labels_true)
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
colors='rgbycm'
for i,label in enumerate(labels):
position=labels_true==label
ax.scatter(X[position,0],X[position,1],label="cluster %d"%label),
color=colors[i%len(colors)]

ax.legend(loc="best",framealpha=0.5)
ax.set_xlabel("X[0]")
ax.set_ylabel("Y[1]")
ax.set_title("data")
#     plt.show()

"""
测试数据
"""
def test_KMeans(*data):
X,labels_true=data
clst=cluster.KMeans()
clst.fit(X)
predicted_labels=clst.predict(X)
print("ARI:%s"% adjusted_rand_score(labels_true, predicted_labels))
print("Sum center distance %s"%clst.inertia_)

"""
考察簇的数量的影响
"""
def test_KMeans_nclusters(*data):
X,labels_true=data
nums=range(1,50)
ARIs=[]
Distances=[]
for num in nums:
clst=cluster.KMeans(n_clusters=num)
clst.fit(X)
predicted_labels=clst.predict(X)
ARIs.append(adjusted_rand_score(labels_true, predicted_labels))
Distances.append(clst.inertia_)

fig=plt.figure()
ax=fig.add_subplot(1,2,1)
ax.plot(nums,ARIs,marker="+")
ax.set_xlabel("n_clusters")
ax.set_ylabel("ARI")
ax=fig.add_subplot(1,2,2)
ax.plot(nums,Distances,marker="o")
ax.set_xlabel("n_clusters")
ax.set_ylabel("inertia")
fig.suptitle("KMeans")
#     plt.show()

"""
考察运行次数和初始中心选择策略的影响
"""
def test_KMeans_n_init(*data):
X,labels_true=data
nums=range(1,50)
fig=plt.figure()
ARIs_k=[]
Distances_k=[]
ARIs_r=[]
Distances_r=[]
for num in nums:
clst=cluster.KMeans(n_init=num,init='k-means++')
clst.fit(X)
predicted_labels=clst.predict(X)
ARIs_k.append(adjusted_rand_score(labels_true, predicted_labels))
Distances_k.append(clst.inertia_)

clst=cluster.KMeans(n_init=num,init='random')
clst.fit(X)
predicted_labels=clst.predict(X)
ARIs_r.append(adjusted_rand_score(labels_true, predicted_labels))
Distances_r.append(clst.inertia_)

ax=fig.add_subplot(1,2,1)
ax.plot(nums,ARIs_k,marker="+",label="k-means++")
ax.plot(nums,ARIs_r,marker="+",label="random")
ax.set_xlabel("n_init")
ax.set_ylabel("ARI")
ax.set_ylim(0,1)
ax.legend(loc="best")
ax=fig.add_subplot(1,2,2)
ax.plot(nums,Distances_k,marker="o",label="k-means++")
ax.plot(nums,Distances_r,marker="o",label="random")
ax.set_xlabel("n_init")
ax.set_ylabel("inertia")
ax.legend(loc="best")

fig.suptitle("KMeans")
plt.show()

centers=[[1,1],[2,2],[1,2],[10,20]]
X,labels_true=create_data(centers, 1000, 0.5)
test_KMeans(X,labels_true)
plot_data(X,labels_true)
test_KMeans_nclusters(X,labels_true)
test_KMeans_n_init(X,labels_true)






可以看到,当n_clusters=4时,ARI指数最大,因为确实是从四个中心点产生的簇。而inertia_在n_clusters=1时最大,因为产生的测试数据有三个中心点较为接近,一个中心点较远。因此如果指定簇的数量为1,及所有的样本都属于一个簇,确实样本离簇中心的距离之和最大。




可以看到ARI指数和inertia_总距离随着n_init震荡,因此这两项指标与n_init影响不是很大,而且随机选择和使用'k-means++'策略选择初始中心向量,对于聚类效果的影响也不大。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python Clustering