一、MLlib简介

MLlib是Spark的机器学习(ML)库。旨在简化机器学习的工程实践工作,并方便扩展到更大规模。MLlib由一些通用的学习算法和工具组成,包括分类、回归、聚类、协同过滤、降维等,同时还包括底层的优化原语和高层的管道API。

MLllib目前分为两个代码包:

  • spark.mllib 包含基于RDD的原始算法API
  • spark.ml 提供了基于DataFrames 高层次的API,可以用来构建机器学习管道

spark开发者推荐使用spark.ml,因为基于DataFrames的API更加的通用而且灵活。不过他们也会继续支持spark.mllib包。 用户可以放心使用,spark.mllib还会持续地增加新的功能。不过需要注意,如果新的算法能够适用于机器学习管道的概念,就应该将其放到 spark.ml包中,如:特征提取器和转换器。

聚类(clustering)方法包括:
1、KMEANS聚类(K-means)
2、二分KMEANS聚类(Bisecting k-means)
3、隐含狄利克雷分布(Latent Dirichlet allocation (LDA))
4、混合高斯分布聚类(Gaussian Mixture Model (GMM))
5、幂迭代聚类 (PIC)
6、流式KMEANS聚类(Streaming k-means)

接下来以利用java api实现spark中的lda算法作为引入,而其他聚类算法的实现过程可参照官方文档

实验中平台及语言版本为:
spark->1.6.2
jdk->1.8
hadoop->2.6


二、LDA实例

lda的原理及实现细则已经有很多优秀的博客阐述,再次不累述。

利用java调用spark中的lda模型代码如下:

import scala.Tuple2;

import org.apache.spark.api.java.*;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.mllib.clustering.DistributedLDAModel;
import org.apache.spark.mllib.clustering.LDA;
import org.apache.spark.mllib.linalg.Matrix;
import org.apache.spark.mllib.linalg.Vector;
import org.apache.spark.mllib.linalg.Vectors;
import org.apache.spark.SparkConf;

public class JavaLDAExample {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setAppName("JavaLdaExample").setMaster("local");
        conf.set("spark.testing.memory", "2147480000");
        JavaSparkContext sc = new JavaSparkContext(conf);

        // 1 加载数据,返回的数据格式为:JavaRDD<Vector>
        // 其中每一个Vector代表文档的词向量
        String path = "/usr/local/spark1.6.2/data/mllib/sample_lda_data.txt";
        JavaRDD<String> data = sc.textFile(path);
        JavaRDD<Vector> parsedData = data.map(new Function<String, Vector>() {
            public Vector call(String s) {
                String[] sarray = s.trim().split(" ");
                double[] values = new double[sarray.length];
                for (int i = 0; i < sarray.length; i++)
                    values[i] = Double.parseDouble(sarray[i]);
                return Vectors.dense(values);
            }
        });

        // 2 转换数据,spark要求的数据格式为 JavaRDD<long, Vector>
        // Long类型指代词向量的索引(唯一标识号)
        // 此处利用zipWithIndex()将vector与vector在RDD的索引组成键值对,并通过swap()调转索引及词向量
        JavaPairRDD<Long, Vector> corpus = JavaPairRDD
                .fromJavaRDD(parsedData.zipWithIndex().map(new Function<Tuple2<Vector, Long>, Tuple2<Long, Vector>>() {
                    public Tuple2<Long, Vector> call(Tuple2<Vector, Long> doc_id) {
                        return doc_id.swap();
                    }
                }));
        corpus.cache(); // 缓存


        // 3 建立模型,设置训练参数,训练模型
        /**
         * k: 主题数,或者聚类中心数 
         * DocConcentration:文章分布的超参数(Dirichlet分布的参数),必需>1.0
         * TopicConcentration:主题分布的超参数(Dirichlet分布的参数),必需>1.0 
         * MaxIterations:迭代次数
         * Seed:随机种子 
         * CheckpointInterval:迭代计算时检查点的间隔
         * Optimizer:优化计算方法,目前支持"em", "online"

         可在创建lda模型时创建
         ldaModel = new lda().setK(5).setSeed(5).setDocConcentration(5);

         也可以通过lda模型获取
         ldaModel.getK();

         */

        DistributedLDAModel ldaModel = (DistributedLDAModel) new LDA().setK(3).run(corpus);

        // 打印主题分布矩阵
        System.out.println("Learned topics (as distributions over vocab of " + ldaModel.vocabSize() + " words):");
        Matrix topics = ldaModel.topicsMatrix();
        for (int topic = 0; topic < 3; topic++) {
            System.out.print("Topic " + topic + ":");
            for (int word = 0; word < ldaModel.vocabSize(); word++) {
                System.out.print(" " + topics.apply(word, topic));
            }
            System.out.println();
        }

        ldaModel.save(sc.sc(), "myLDAModel"); // 缓存模型
        DistributedLDAModel sameModel = DistributedLDAModel.load(sc.sc(), "myLDAModel"); // 读取模型
    }
}

LDA模型说明:

1、spark中DistributedLDAMode继承自LDAModel,其中LDAModel主要用来初始化LDA模型,而DistributedLDAModel中提供运算的结果

DistributedLDAMode比较重要的函数有:

1、topTopicsPerDocument(int k):
对于每一个输入的文档,按权重排序,返回前k个主题。

Parameters:
  k - (undocumented)
Returns:
  RDD of (doc ID, topic indices, topic weights)


2、topicDistributions():
得到文档下的主题分布。

Returns:
  RDD of (document ID, topic distribution) pairs


3、 topicsMatrix():
得到主题下的词条分布。

Returns:
  Matrix:
    Matrix(word_id, topic_id)表示特定主题下特定单词的权重

可用 weight = Matrix.apply(word_id, topic_id) 获得


4、describeTopics( int k):
按权重排序,返回各个主题下前k个词

Parameters:
  maxTermsPerTopic - 需要返回前几个词
Returns:
  Array over topics. Each topic is represented as a pair of matching arrays: (term indices, term weights in topic). Each topic’s terms are sorted in order of decreasing weight.


可能遇到的问题:

1、”A master URL must be set in your configuration” 缺乏配置主机
解决办法:创建SparkConf对象时设置主机

new SparkConf().setMaster("local");

2、”Failed to connect to master”主机配置错误
解决方法:请参照一下spark配置资料

3、” java.lang.IllegalArgumentException: System memory 468189184 must be at least 4.718592E8 “JVM申请的memory不够导致无法启动SparkContext
解决办法:

(1). 自己的源代码处,可以在conf之后加上:

SparkConf conf = new SparkConf().setAppName("JavaLDAExample").setMaster("local");
conf.set("spark.testing.memory", "2147480000");

(2). 可以在Eclipse的Run Configuration处,有一栏是Arguments,下面有VMarguments,在下面添加下面一行(值也是只要大于512m即可)

-Dspark.testing.memory=1073741824

三、参考文档


spark配置指南
spark配置官方资料(1.6.2版本)
spark-mllib数据类型
spark-mllib-ldamodel类文档
spark-mllib-DistributedLDAModel类文档