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

Java 8 使用java 8计算文件中两个单词的概率分布,java-8,lucene,stanford-nlp,probability-distribution,Java 8,Lucene,Stanford Nlp,Probability Distribution,我需要包含两个单词的行数。为此,我编写了以下代码: 输入文件包含1000行和大约4000个字,大约需要4个小时。 Java中是否有一个库可以更快地完成这项工作? 我可以使用Appache Lucene或Stanford Core NLP来实现这段代码以减少运行时间吗 ArrayList<String> reviews = new ArrayList<String>(); ArrayList<String> terms = new ArrayList<St

我需要包含两个单词的行数。为此,我编写了以下代码: 输入文件包含1000行和大约4000个字,大约需要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);
                }
            }
    }

获取不同单词的第一个循环依赖于ArrayList.contains,它具有线性时间复杂度,而不是使用集合。因此,如果我们假设nd个不同的单词,它的时间复杂度已经是“行数”×nd

然后,您将创建nd×nd单词组合,并探测所有1000行中是否存在这些组合。换句话说,如果我们只假设100个不同的单词,那么您正在执行1000×100+100×100×1000=10100000个操作,如果我们假设500个不同的单词,那么我们已经在谈论250500000个

相反,您应该只创建一行中实际存在的组合,并将它们收集到地图中。这将只处理那些实际存在的组合,您可以通过只检查每个“a_b”/“b_a”组合中的任何一个来改进这一点,因为两者的概率相同。然后,您只执行“行数”ד每行字”ד每行字”操作,换句话说,在您的案例中大约有16000个操作

以下方法组合一行中的所有单词,只保留“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();
}


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

获取不同单词的第一个循环依赖于ArrayList.contains,它具有线性时间复杂度,而不是使用集合。因此,如果我们假设nd个不同的单词,它的时间复杂度已经是“行数”×nd

然后,您将创建nd×nd单词组合,并探测所有1000行中是否存在这些组合。换句话说,如果我们只假设100个不同的单词,那么您正在执行1000×100+100×100×1000=10100000个操作,如果我们假设500个不同的单词,那么我们已经在谈论250500000个

相反,您应该只创建一行中实际存在的组合,并将它们收集到地图中。这将只处理那些实际存在的组合,您可以通过只检查每个“a_b”/“b_a”组合中的任何一个来改进这一点,因为两者的概率相同。然后,您只执行“行数”ד每行字”ד每行字”操作,换句话说,在您的案例中大约有16000个操作

以下方法组合一行中的所有单词,只保留“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();
}


要将代码概括为使用不同的输入,请处理多个空格或其他标点符号,并忽略大小写。

库并不是万能的。代码不是因为没有使用库而变慢,而是因为使用了包含另一个流操作的两个嵌套循环而变慢。也就是说,term.size×term.size×reviews.size操作。没错,但这是不可避免的。因此,我认为有可能使用更快的方法,而不是使用ParllelStream@霍尔格:这不是不可避免的。这就是开发算法的艺术。这就是为什么我们知道这么多不同的排序算法;解决同一个任务有许多不同的方法,你永远不会认为没有更好的方法。库不是魔法。代码不是因为没有使用库而变慢,而是因为使用了包含另一个流操作的两个嵌套循环而变慢。也就是说,term.size×term.size×reviews.size操作。没错,但这是不可避免的。因此,我认为有可能使用更快的方法,而不是使用ParllelStream@霍尔格:这不是不可避免的。这就是开发算法的艺术。这就是为什么我们知道这么多不同的排序算法;解决同一个任务有许多不同的方法,你永远不会认为没有更好的方法了。有一种观点认为,实际的书名应该是战争和人类星球、光、地球等等——就像一个没有定义的词一样!=战争与和平。最初它被写为“我是!”和平现在,这被视为第一本印刷书中的一个打字错误,或者是一个单词和平,这个名字很可能会随着战争与和平而流传anyway@Eugene:我不知道革命前世界与和平有两个截然不同的词;我只知道这两个字的意思。但无论如何,你的假设是正确的,我们将继续使用这个众所周知的名字,以确保读者也知道我们不知道什么
谈到……有一种观点认为,真正的书名应该是战争和人类星球、光、地球等等——就像一个没有定义的词一样!=战争与和平。最初它被写为“我是!”和平现在,这被视为第一本印刷书中的一个打字错误,或者是一个单词和平,这个名字很可能会随着战争与和平而流传anyway@Eugene:我不知道革命前世界与和平有两个截然不同的词;我只知道这两个字的意思。但无论如何,你的假设是正确的,我们将继续使用这个众所周知的名字,以确保读者也知道我们在谈论什么…
String[] words = line.split(" ");
String[] words = line.toLowerCase().split("\\W+");