MapReduce之 K K K-均值聚类
背景
什么是聚类?什么是K-均值算法?基本来说,给定 K > 0 K>0 K>0,( K K K为簇数)和一个集合(其中包括需要聚类的 N N N个 d d d-维对象):
- 聚类是将 N N N个 d − d- d−维(2-维,3-维等)对象分组为 K K K个了类似对象簇的过程
- 同一个簇中的对象彼此类似,而不同簇中的对象彼此相异
K K K-均值算法是一个基于距离的聚类算法, K K K-均值聚类有很多应用,可以用来找出有共同行为的一组消费者,或者根据文档内容的相似性对文档完成聚类,如:
- 市场营销
给定一个很大的顾客交易集,找出有类似购买行为的顾客分组 - 文档分类
对Web日志数据分类,发现有类似访问模式的分组 - 保险
通过识别可能的欺诈行为找出平均索赔支出很高的车险投保人群
什么是 K K K-均值聚类
在一个二维环境中,输入数据可能如下,其中每行表示一个点(x,y):
p
1
=
(
1
,
1
)
p_1=(1,1)
p1=(1,1)
p
2
=
(
2
,
1
)
p_2=(2,1)
p2=(2,1)
p
3
=
(
1
,
2
)
p_3=(1,2)
p3=(1,2)
p
4
=
(
5
,
5
)
p_4=(5,5)
p4=(5,5)
p
5
=
(
6
,
5
)
p_5=(6,5)
p5=(6,5)
p
6
=
(
5
,
6
)
p_6=(5,6)
p6=(5,6)
p
7
=
(
7
,
7
)
p_7=(7,7)
p7=(7,7)
p
8
=
(
9
,
6
)
p_8=(9,6)
p8=(9,6)
开始时,会选择K个点作为簇中心,这些点作为簇质心。可以采用很多方法来初始化簇的质心,其中一种方法是从n个点的样本中随即选取K个点,一旦选择的K个初始的簇质心,可以计算输入集合中各个点到这K个中心点的距离,然后将各个点分配到与它最近的簇中心。所有对象分配结束后,在重新计算K个质心的位置。这两步反复迭代,直到簇中心不再改变(或变化范围小于阈值)。这就是一个基本的K-均值聚类过程。
K K K-均值聚类的形式化表述如下:
给定
n
n
n个
d
d
d-维点:
X
1
=
(
x
11
,
x
12
,
…
,
x
1
d
)
X_1=(x_{11},x_{12},\dots,x_{1d} )
X1=(x11,x12,…,x1d)
X
2
=
(
x
21
,
x
22
,
…
,
x
2
d
)
X_2=(x_{21},x_{22},\dots,x_{2d})
X2=(x21,x22,…,x2d)
…
\dots
…
X
n
=
(
x
n
1
,
x
n
2
,
…
,
x
n
d
)
X_n=(x_{n1},x_{n2},\dots,x_{nd})
Xn=(xn1,xn2,…,xnd)
将这个{
X
1
,
X
2
,
…
,
X
n
{X_1,X_2,\dots,X_n}
X1,X2,…,Xn}划分为K个簇:{
C
1
,
C
2
,
.
.
.
,
C
k
)
C_1,C_2,...,C_k)
C1,C2,...,Ck).K-均值算法的目的是找出这些簇的位置
μ
i
(
i
=
i
,
…
,
K
)
\mu_i(i=i,\dots,K)
μi(i=i,…,K),使数据点到簇质心的距离最小。K-均值聚类可以解决以下最小代代价算法:
a
r
g
m
i
n
c
∑
i
=
1
k
∑
X
j
ϵ
C
i
∥
X
j
−
μ
i
∥
2
arg min_c\sum_{i=1}^k\sum_{X_j\epsilon C_i}\parallel X_j-\mu_i\parallel^2
argminc∑i=1k∑XjϵCi∥Xj−μi∥2
其中
μ
i
\mu_i
μi是
C
i
C_i
Ci中点的平均值,
∥
x
i
j
−
c
j
∥
\parallel x_i^j-c_j\parallel
∥xij−cj∥为实体点与簇质心之间的距离
K K K-均值聚类方法非形式化描述:分区方法
因为K-均值聚类算法是迭代的,在下面即将介绍的MapReduce实现中,通过不断运行MapReduce解决方案,直到找到一个和是的最优解决方案,使K-均值聚类算法收敛。K-均值算法需要完成以下几个步骤:
- 1、将 N N N个对象划分到 K K K个非空子集中。
- 2、计算当前分区中的簇质心(质心是这个簇的中心)。对于所有
i
=
1
,
2
,
…
,
K
,
μ
i
i=1,2,\dots,K,\mu_i
i=1,2,…,K,μi计算为:
μ i = 1 ∣ c i ∣ ∑ j ϵ C i x j ˉ , ∨ i \mu_i=\frac{1}{|c_i|}\sum_{j\epsilon C_i}\bar{x_j}, \vee i μi=∣ci∣1∑jϵCixjˉ,∨i - 3、将各个对象分配到有最近质心的簇,这样会为各个数据点找到最近的簇:
c i = { j : d ( x j , μ i ) ≤ d ( x j , u 1 ) , 1 ≠ i , j = 1 , … , n } c_i=\{j:d(x_j,\mu_i)\le d(x_j,u_1),1\not=i,j=1,\dots,n\} ci={j:d(xj,μi)≤d(xj,u1),1=i,j=1,…,n}
其中 d ( a , b ) d(a,b) d(a,b)是两个点a和b的距离函数。 - 4、如果不再有新的分配,则停止计算,否则回到第二步。一般需要重复步骤2和3直到算法收敛。
这个算法会反复迭代,直到质心不再变化,此时就找到了我们需要的K个簇,由于K-均值算法是一个迭代过程,每一步都会根据各个现有簇的当前中心重新计算簇中的各个对象的成员关系。这个过程会反复进行,直到达到期望的簇数。
K K K-均值距离函数
K K K-均值聚类算法的第一步需要把各个数据点分配到最近的簇质心。对于一个给定的( d d d维)数据点,可以使用一个距离函数来确定最近的簇质心,这个函数会计算这个质心生成该数据点的可能性有多大,有很多距离函数可以使用,包括:
- 欧氏距离
- 曼哈顿距离
- 内积空间
- 最大模
- 自定义函数(可以是 d d d维空间上定义的任何度量函数)
很多
K
K
K-均值算法中都使用了欧氏距离。要的出两个数据点实例
X
X
X和
Y
Y
Y(表示为
d
d
d个连续属性,即
d
d
d-维)之间的欧氏距离:
令:
X
=
(
X
1
,
X
2
,
…
,
X
d
)
X=(X_1,X_2,\dots,X_d)
X=(X1,X2,…,Xd)
Y
=
(
Y
1
,
Y
2
,
…
,
Y
d
)
Y=(Y_1,Y_2,\dots,Y_d)
Y=(Y1,Y2,…,Yd)
则有:
d
i
s
t
a
n
c
e
(
X
,
Y
)
=
(
X
1
−
Y
1
)
2
+
(
X
2
−
Y
2
)
2
+
⋯
+
(
X
d
−
Y
d
)
2
distance(X,Y)=\sqrt{(X_1-Y_1)^2+(X_2-Y_2)^2+\dots+(X_d-Y_d)^2}
distance(X,Y)=(X1−Y1)2+(X2−Y2)2+⋯+(Xd−Yd)2
欧氏距离有以下性质:
- d i s t a n c e ( i , j ) ≥ 0 distance(i,j)\geq0 distance(i,j)≥0
- d i s t a n c e ( i , j ) = 0 distance(i,j)=0 distance(i,j)=0
- d i s t a n c e ( i , j ) = d i s t a n c e ( j , i ) distance(i,j)=distance(j,i) distance(i,j)=distance(j,i)
- d i s t a n c e ( i , j ) ≤ d i s t a n c e ( i , k ) + d i s t a n c e ( k , j ) distance(i,j)\leq distance(i,k)+distance(k,j) distance(i,j)≤distance(i,k)+distance(k,j)
一个简单的欧氏距离函数为代码如下:
public class EuclideanDistance{
// center 为簇质心
//令vector[i]表示第i个位置代表的属性
public static double calculateDistance(Vector center,Vector data){
double sum=0.0;
int length=data.length;
//计算每个属性之间的距离
for(int i=0;i<length;i++){
sum+=Math.pow((center[i]-data[i]),2.0);
}
return Math.sqrt(sum);
}
}
在下一篇博客中,将会介绍如何利用MapReduce实现 K K K-均值聚类算法