使用java 8在文件中使用两个单词的概率分布

1 lucene stanford-nlp java-8 probability-distribution

我需要包含两个单词的行数.为此,我编写了以下代码:输入文件包含1000 lines和关于4,000 words,大约需要4个小时.是否有一个库Java可以更快地完成它?我可以使用Appache Lucene或实现此代码Stanford Core NLP以减少运行时间吗?

ArrayList<String> reviews = new ArrayList<String>();
ArrayList<String> terms = new ArrayList<String>();
Map<String,Double> pij = new HashMap<String,Double>();

BufferedReader br = null;
FileReader fr = null;
try 
    {
        fr = new FileReader("src/reviews-preprocessing.txt");
            br = new BufferedReader(fr);
            String line;
            while ((line= br.readLine()) != null) 
            {
            for(String term : line.split(" "))
                {
                    if(!terms.contains(term))
                        terms.add(term);
                }
                reviews.add(line);
            }
        } 
        catch (IOException e) { e.printStackTrace();} 
        finally 
        {
            try 
            {
                if (br != null)
                    br.close();
                if (fr != null)
                    fr.close();
            } 
            catch (IOException ex) { ex.printStackTrace();}    
    }
long Count = reviews.size();
for(String term_i : terms)
    {
        for(String term_j : terms)
            {
                if(!term_i.equals(term_j))
                {
                    double p = (double) reviews.parallelStream().filter(s -> s.contains(term_i) && s.contains(term_j)).count();
                    String key = String.format("%s_%s", term_i,term_j);
                    pij.put(key, p/Count);
                }
            }
    }
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 6

你的第一个循环得到不同的单词依赖于ArrayList.contains,它具有线性时间复杂度,而不是使用Set.因此,如果我们假设nd个不同的单词,它已经具有" 行数nd的时间复杂度.

然后,您正在创建nd × nd单词组合,并探测所有1,000行是否存在这些组合.换句话说,如果我们只假设100个不同的单词,那么你正在执行1,000×100 + 100×100×1,000 = 10,100,000个操作,如果我们假设500个不同的单词,我们已经讨论了250,500,000个单词.

相反,您应该只创建实际存在于一行中的组合并将它们收集到地图中.这将仅处理实际存在的那些组合,并且您可以通过仅检查每个"a_b"/"b_a"组合中的任一个来改进这一点,因为两者的概率相同.然后,您只执行" 行数 "×" 每行字数 "×" 每行字数 "操作,换句话说,在您的情况下执行大约16,000次操作.

以下方法组合了一行的所有单词,只保留了一个"a_b"/"b_a"组合,并消除了重复,因此每个组合都可以算作一行.

static Stream<String> allCombinations(String line) {
    String[] words = line.split(" ");
    return Arrays.stream(words)
        .flatMap(word1 ->
            Arrays.stream(words)
                  .filter(words2 -> word1.compareTo(words2)<0)
                  .map(word2 -> word1+'_'+word2))
        .distinct();
}
Run Code Online (Sandbox Code Playgroud)

这种方法可以使用

List<String> lines = Files.readAllLines(Paths.get("src/reviews-preprocessing.txt"));
double ratio = 1.0/lines.size();
Map<String, Double> pij = lines.stream()
        .flatMap(line -> allCombinations(line))
        .collect(Collectors.groupingBy(Function.identity(),
                                       Collectors.summingDouble(x->ratio)));
Run Code Online (Sandbox Code Playgroud)

它在几秒钟内完成了我的"战争与和平"副本,无需任何尝试进行并行处理.并不奇怪,"and_the"是概率最高的组合.

您可以考虑更改该行

String[] words = line.split(" ");
Run Code Online (Sandbox Code Playgroud)

String[] words = line.toLowerCase().split("\\W+");
Run Code Online (Sandbox Code Playgroud)

概括代码以使用不同的输入,处理多个空格或其他标点字符并忽略大小写.

  • 有一种观点认为,实际的书籍名称应该是"战争和人性(行星,光,地球)"等 - 就像一个没有定义`!= war && == peace`的词.最初它被写成`мiръ`(这是`!= peace`).现在这被视为第一本印刷书籍中的拼写错误或者是一个词!=和平,无论如何,这个名字可能会留下"战争与和平" (2认同)
  • @Eugene:我不知道革命前世界和和平有两个不同的词; 我只知道"мир"意味着两者.但无论如何,你的假设是对的,我们将继续使用这个众所周知的名字来确保读者也知道我们在说什么...... (2认同)