转自 程序员的自我修养 – SelfUp.cn
由于在学习 spark mllib 但是如此详细的资料真的很难找,在此分享。
聚类,Cluster analysis,有时也被翻译为簇类,其核心任务是:将一组目标object划分为若干个簇,每个簇之间的object尽可能的相似,簇与簇之间的object尽可能的相异。聚类算法是机器学习(或者说是数据挖掘更合适)中重要的一部分,除了最为简单的K-Means聚类算法外,较常见的还有:层次法(CURE、CHAMELEON等)、网格算法(STING、WaveCluster等)等等。
较权威的聚类问题定义:所谓聚类问题,就是给定一个元素集合D,其中每个元素具有n个可观察属性,使用某种算法将D划分成k个子集,要求每个子集内部的元素之间相异度尽可能低,而不同子集的元素相异度尽可能高。其中每个子集叫做一个簇。
与分类不同,分类是示例式学习,要求分类前明确各个类别,并断言每个元素映射到一个类别,而聚类是观察式学习,在聚类前可以不知道类别甚至不给定类别数量,是无监督学习的一种。目前聚类广泛应用于统计学、生物学、数据库技术和市场营销等领域,相应的算法也非常的多。
K-Means属于基于平方误差的迭代重分配聚类算法,其核心思想十分简单:
K-Means算法的结果好坏依赖于对初始聚类中心的选择,容易陷入局部最优解,对K值的选择没有准则可依循,对异常数据较为敏感,只能处理数值属性的数据,聚类结构可能不平衡。
这里有一个K-Means的演示,需要安装Java Applet。
1
2
3
4
5
6
7
8
9
|
0.0
0.0
0.0
0.1
0.1
0.1
0.2
0.2
0.2
9.0
9.0
9.0
9.1
9.1
9.1
9.2
9.2
9.2
15.1
16.1
17.0
18.0
17.0
19.0
20.0
21.0
22.0
|
如前文所述,测试数据不用带标签,数据分为3个维度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
private
static
final
Pattern
SPACE
=
Pattern
.
compile
(
" "
)
;
public
static
void
main
(
String
[
]
args
)
{
SparkConf
sparkConf
=
new
SparkConf
(
)
.
setAppName
(
"K-Means"
)
.
setMaster
(
"local[2]"
)
;
JavaSparkContext
sc
=
new
JavaSparkContext
(
sparkConf
)
;
JavaRDD
<
String
>
data
=
sc
.
textFile
(
"/home/yurnom/data/kmeans_data.txt"
)
;
JavaRDD
<
Vector
>
parsedData
=
data
.
map
(
s
->
{
double
[
]
values
=
Arrays
.
asList
(
SPACE
.
split
(
s
)
)
.
stream
(
)
.
mapToDouble
(
Double
::
parseDouble
)
.
toArray
(
)
;
return
Vectors
.
dense
(
values
)
;
}
)
;
int
numClusters
=
3
;
//预测分为3个簇类
int
numIterations
=
20
;
//迭代20次
int
runs
=
10
;
//运行10次,选出最优解
KMeansModel
clusters
=
KMeans
.
train
(
parsedData
.
rdd
(
)
,
numClusters
,
numIterations
,
runs
)
;
//计算测试数据分别属于那个簇类
print
(
parsedData
.
map
(
v
->
v
.
toString
(
)
+
" belong to cluster :"
+
clusters
.
predict
(
v
)
)
.
collect
(
)
)
;
//计算cost
double
wssse
=
clusters
.
computeCost
(
parsedData
.
rdd
(
)
)
;
System
.
out
.
println
(
"Within Set Sum of Squared Errors = "
+
wssse
)
;
//打印出中心点
System
.
out
.
println
(
"Cluster centers:"
)
;
for
(
Vector
center
:
clusters
.
clusterCenters
(
)
)
{
System
.
out
.
println
(
" "
+
center
)
;
}
//进行一些预测
System
.
out
.
println
(
"Prediction of (1.1, 2.1, 3.1): "
+
clusters
.
predict
(
Vectors
.
dense
(
new
double
[
]
{
1.1
,
2.1
,
3.1
}
)
)
)
;
System
.
out
.
println
(
"Prediction of (10.1, 9.1, 11.1): "
+
clusters
.
predict
(
Vectors
.
dense
(
new
double
[
]
{
10.1
,
9.1
,
11.1
}
)
)
)
;
System
.
out
.
println
(
"Prediction of (21.1, 17.1, 16.1): "
+
clusters
.
predict
(
Vectors
.
dense
(
new
double
[
]
{
21.1
,
17.1
,
16.1
}
)
)
)
;
}
public
static
<
T
>
void
print
(
Collection
<
T
>
c
)
{
for
(
T
t
:
c
)
{
System
.
out
.
println
(
t
.
toString
(
)
)
;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[
0.0
,
0.0
,
0.0
]
belong
to
cluster
:
0
[
0.1
,
0.1
,
0.1
]
belong
to
cluster
:
0
[
0.2
,
0.2
,
0.2
]
belong
to
cluster
:
0
[
9.0
,
9.0
,
9.0
]
belong
to
cluster
:
1
[
9.1
,
9.1
,
9.1
]
belong
to
cluster
:
1
[
9.2
,
9.2
,
9.2
]
belong
to
cluster
:
1
[
15.1
,
16.1
,
17.0
]
belong
to
cluster
:
2
[
18.0
,
17.0
,
19.0
]
belong
to
cluster
:
2
[
20.0
,
21.0
,
22.0
]
belong
to
cluster
:
2
Within
Set
Sum
of
Squared
Errors
=
38.533333333333815
Cluster
centers
:
[
0.10000000000000002
,
0.10000000000000002
,
0.10000000000000002
]
[
9.1
,
9.1
,
9.1
]
[
17.7
,
18.033333333333335
,
19.333333333333332
]
Prediction
of
(
1.1
,
2.1
,
3.1
)
:
0
Prediction
of
(
10.1
,
9.1
,
11.1
)
:
1
Prediction
of
(
21.1
,
17.1
,
16.1
)
:
2
|
人为捏造的测试数据所想表现出来的簇类完全被k-means算法体会到了,若是人工将测试数据分成3个簇类,结果也会与上面一样。
K-Means属于无监督学习,最大的特别和优势在于模型的建立不需要训练数据。在日常工作中,很多情况下没有办法事先获取到有效的训练数据,这时采用K-Means是一个不错的选择。但K-Means需要预先设置有多少个簇类(K值),这对于像计算某省份全部电信用户的交往圈这样的场景就完全的没办法用K-Means进行。对于可以确定K值不会太大但不明确精确的K值的场景,可以进行迭代运算,然后找出cost最小时所对应的K值,这个值往往能较好的描述有多少个簇类。