Java Spark 1.3.1中的LDA。将原始数据转换为术语文档矩阵?

Java Spark 1.3.1中的LDA。将原始数据转换为术语文档矩阵?,java,apache-spark,lda,Java,Apache Spark,Lda,我正在使用Java中的Spark 1.3.1试用LDA,出现以下错误: Error: application failed with exception org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 0.0 failed 1 times, most recent failure: Lost task 0.0 in stage 0.0 (TID 0, localhost): ja

我正在使用Java中的Spark 1.3.1试用LDA,出现以下错误:

Error: application failed with exception
org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 0.0 failed 1 times, most recent failure: Lost task 0.0 in stage 0.0 (TID 0, localhost): java.lang.NumberFormatException: For input string: "��"
我的.txt文件如下所示: 增加体重现在发现困难的引体向上俯卧撑 失明疾病所有的眼睛都工作得很好,除了能用光照图像 模范儿童 亲爱的回忆最悲伤的童年

代码如下:

import scala.Tuple2;

import org.apache.spark.api.java.*;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.mllib.clustering.LDAModel;
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 JavaLDA {
  public static void main(String[] args) {
    SparkConf conf = new SparkConf().setAppName("LDA Example");
    JavaSparkContext sc = new JavaSparkContext(conf);

    // Load and parse the data
    String path = "/tutorial/input/askreddit20150801.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);
          }
        }
    );
    // Index documents with unique IDs
    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();

    // Cluster the documents into three topics using LDA
    LDAModel ldaModel = new LDA().setK(100).run(corpus);

    // Output topics. Each is a distribution over words (matching word count vectors)
    System.out.println("Learned topics (as distributions over vocab of " + ldaModel.vocabSize()
        + " words):");
    Matrix topics = ldaModel.topicsMatrix();
    for (int topic = 0; topic < 100; 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");

  }
}
导入scala.Tuple2;
导入org.apache.spark.api.java.*;
导入org.apache.spark.api.java.function.function;
导入org.apache.spark.mllib.clustering.LDAModel;
导入org.apache.spark.mllib.clustering.LDA;
导入org.apache.spark.mllib.linalg.Matrix;
导入org.apache.spark.mllib.linalg.Vector;
导入org.apache.spark.mllib.linalg.Vectors;
导入org.apache.spark.SparkConf;
公共类JavaLDA{
公共静态void main(字符串[]args){
SparkConf conf=new SparkConf().setAppName(“LDA示例”);
JavaSparkContext sc=新的JavaSparkContext(conf);
//加载并解析数据
字符串路径=“/tutorial/input/askreddit20150801.txt”;
JavaRDD data=sc.textFile(路径);
JavaRDD parsedData=data.map(
新函数(){
公共向量调用(字符串s){
字符串[]sarray=s.trim().split(“”);
double[]值=新的double[sarray.length];
for(int i=0;i
有人知道为什么会这样吗?我只是第一次尝试火花。谢谢

values[i] = Double.parseDouble(sarray[i]);
为什么要将文本文件中的每个单词转换为双精度

这就是你问题的答案:

您的代码希望输入文件是一组看起来像数字的以空格分隔的文本行。假设您的文本是文字:

获取语料库中出现的每个单词的列表:

JavaRDD<String> words =
        data.flatMap((FlatMapFunction<String, String>) s -> {
            s = s.replaceAll("[^a-zA-Z ]", "");
            s = s.toLowerCase();
            return Arrays.asList(s.split(" "));
        });
这将导致矢量的RDD,其中每个矢量都是vocab.size()长,矢量中的每个点都是vocab单词在行中出现的次数


我从当前使用的代码中稍微修改了这段代码,但没有对其进行测试,因此可能会有错误。祝你好运

这与LDA无关!您正在尝试将字符串转换为数字。检查一下!我从这里取了密码。我只是将DistributedLDAModel更改为LDAModel,这是什么意思?你真的读过你的错误信息吗?“java.lang.NumberFormatException:用于输入字符串:”��”“我告诉你,这不是问题所在。问题是你试图解析的输入。哦,我明白你的意思了。我以为你说我不应该把单词转换成频率。我从这里取了代码。我只是把DistributedLDAModel改成了LDAModel,他们为什么要这样做?因为他们的输入确实是双重的:但是你加载的纯文本链接错误。对不起:这是给lda的:我明白了。所以他们已经把文件转换成了TermDocumentMatrix。在Spark中有没有办法做到这一点?我找到了这个,但我认为这不是解决办法。是的,您必须将文档转换为术语计数向量。您想要的是使用CountVectorizer:这段代码不起作用,因为您对输入文本进行了预处理,替换了所有非字母数字字符并使用小写字母,但在JavaRDD构建中,您只按空间分割,因此无法在vocab映射中找到一些标记。您的代码抛出NullPointerException。但为了避免这个错误,这是一个很好的解释,它帮助我解决了我对这个问题的疑虑。谢谢。另一个错误:在创建词汇表之前,您需要对单词RDD应用一个不同的操作,因为您可能会发现重复的单词,并且当应用zipWithIndex时,行“idx[vocab.get(val).intValue()]可能会返回NullPointerException。
Map<String, Long> vocab = words.zipWithIndex().collectAsMap();
JavaRDD<Vector> tokens = data.map(
        (Function<String, Vector>) s -> {
            String[] vals = s.split("\\s");
            double[] idx = new double[vocab.size() + 1];
            for (String val : vals) {
                idx[vocab.get(val).intValue()] += 1.0;
            }
            return Vectors.dense(idx);
        }
    );