mllib在实现kmeans的过程中,对于距离的计算,使用了一些技巧。
首先要注意的是,mllib的jar中包org.apache.spark.mllib.linalg下定义了DenseVector,SparseVector,Vector等类或对象或特质。但实际上在真正计算过程中,mllib都是使用的breeze.linalg中的DenseVector,SparseVector,Vector等,mllib做了一个类似适配器的东西。所以名称不产生混乱,在import
breeze.linalg时都对相应的名称进行了重命名,比如Vectors.scala中的import breeze.linalg.{DenseVector => BDV, SparseVector => BSV, Vector => BV},KMeans.scala中的import breeze.linalg.{DenseVector => BDV, Vector => BV, norm => breezeNorm}。
将
org.apache.spark.mllib.linalg下的Vector转化为BV就是使用一个方法toBreeze。
在进行kmeans运行之前,会先给每一个向量数据计算一个norms,如果向量是(a, b),则norms就是
。计算出norms后再与原向量做一个匹配zip,最后new出一个
BreezeVectorWithNorm对象,这是一个包含
BreezeVector和该向量的norm的一个对象。
def run(data: RDD[Vector]): KMeansModel = {
// Compute squared norms and cache them.
val norms = data.map(v => breezeNorm(v.toBreeze, 2.0))
norms.persist()
val breezeData = data.map(_.toBreeze).zip(norms).map { case (v, norm) =>
new BreezeVectorWithNorm(v, norm)