【问题标题】:LDA in Spark 1.3.1. Converting raw data into Term Document Matrix?Spark 1.3.1 中的 LDA。将原始数据转换为术语文档矩阵?
【发布时间】:2017-09-25 06:32:09
【问题描述】:

我在 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");

  }
}

有人知道为什么会这样吗?我只是第一次尝试 LDA Spark。谢谢。

【问题讨论】:

  • 这与LDA无关!您正在尝试将字符串转换为数字。检查一下!
  • 我从这里获取了代码。我只将 DistributedLDAModel 更改为 LDAModel spark.apache.org/docs/latest/mllib-clustering.html
  • 这是什么意思?你真的读过你的错误信息吗? “java.lang.NumberFormatException:对于输入字符串:“��”“
  • 我告诉你,这不是问题所在。问题在于您尝试解析的输入。
  • 哦,我明白你的意思了。我以为你说我不应该将单词转换为频率。

标签: java apache-spark lda


【解决方案1】:
values[i] = Double.parseDouble(sarray[i]);

您为什么要将文本文件中的每个单词都转换为 Double?

这就是您的问题的答案: http://docs.oracle.com/javase/6/docs/api/java/lang/Double.html#parseDouble%28java.lang.String%29

【讨论】:

【解决方案2】:

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

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

JavaRDD<String> words =
        data.flatMap((FlatMapFunction<String, String>) s -> {
            s = s.replaceAll("[^a-zA-Z ]", "");
            s = s.toLowerCase();
            return Arrays.asList(s.split(" "));
        });

制作一张地图,给每个单词一个与之相关的整数:

Map<String, Long> vocab = words.zipWithIndex().collectAsMap();

然后,不要让您的 parsedData 在上面做它正在做的事情,而是让它查找每个单词,找到相关的数字,转到数组中的那个位置,然后将该单词的计数加 1。

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);
        }
    );

这会产生一个向量的 RDD,其中每个向量都是 vocab.size() 长,向量中的每个点都是该 vocab 单词在该行中出现的次数的计数。

我对当前使用的代码稍作修改,并没有对其进行测试,因此其中可能存在错误。祝你好运!

【讨论】:

  • 此代码不起作用,因为您预处理了输入文本,替换了所有非字母数字字符并应用小写,但在您的 JavaRDD 构建中,您仅按空格分隔,因此无法找到一些vocab 映射中的标记。您的代码会引发 NullPointerException。但是避免这个错误,这是一个很好的解释,它帮助我解决了我对这个问题的疑虑。谢谢。
  • 另一个错误:您需要在创建词汇表之前对 words RDD 应用 distinct 操作,因为您可能会发现重复的单词以及当 应用 zipWithIndex 行“idx[vocab.get(val).intValue()] 可能返回 NullPointerException。
猜你喜欢
  • 2018-05-04
  • 1970-01-01
  • 2017-07-07
  • 1970-01-01
  • 2021-07-27
  • 2018-06-24
  • 2017-10-16
  • 2015-01-29
  • 1970-01-01
相关资源
最近更新 更多