2015-12-31 2 views
0

Я пишу программу Java, которая в одной части пытается найти все слова, которые совместно встречаются в предложении вместе и подсчитывают их частоту.Более эффективный способ найти частоту рядов bigrams

Основная проблема заключается в том, что код кажется очень неэффективным, и текст, который я пытаюсь извлечь из этих Ranged Bigrams, является относительно большим (70000 уникальных форм слова, токены 2.5M).

Я использую векторное пространство для появления каждого уникального слова в тексте. а затем сравните их, чтобы увидеть, происходят ли два слова в одном предложении.

Вот мой код:

public static HashMap<Pair<String>, Double> flexGramCountEVSM(HashMap<String, ArrayList<Double>> wordVector, String delimiter) { 
    HashMap<Pair<String>, Double> bigramFrequencies = new HashMap<>(); 
    Pair<String> thisBigram; 
    String word1, word2; 

    ArrayList<String> keys = new ArrayList<>(wordVector.keySet()); 
    ArrayList<Double> delims = wordVector.get(delimiter); 


    for (int i = 0; i < keys.size(); i++) { 
     if (i % 1 == 0) System.out.println("---> " + i); 
     word1 = keys.get(i); 
     if (word1.equals(delimiter)) continue; 
     // First Word Occurrences: 
     ArrayList<Double> a = wordVector.get(word1); 

     for (int j = i + 1; j < keys.size(); j++) { 
      word2 = keys.get(j); 
      if (word2.equals(delimiter)) continue; 
      // Second Word Occurrences: 
      ArrayList<Double> b = wordVector.get(word2); 

      thisBigram = new Pair<>(word1, word2); 
      int a1, a2, b1, b2, d1, d2, thisBigramCount = 0; 


      if (a.size() <= b.size()) { 
       for (Double posA : a) { 
        d2 = -Collections.binarySearch(delims, posA) - 1; 
        d1 = d2 != 0 ? (d2 - 1) : d2; 

        b1 = -Collections.binarySearch(b, delims.get(d1)) - 1; 
        b2 = -Collections.binarySearch(b, delims.get(d2)) - 1; 

        if (b2 > b1) { 
         thisBigramCount += b2 - b1; 
        } 
       } 
      } else { 
       for (Double posB : b) { 
        d2 = -Collections.binarySearch(delims, posB) - 1; 
        d1 = d2 != 0 ? (d2 - 1) : d2; 

        a1 = -Collections.binarySearch(a, delims.get(d1)) - 1; 
        a2 = -Collections.binarySearch(a, delims.get(d2)) - 1; 

        if (a2 > a1) { 
         thisBigramCount += a2 - a1; 
        } 
       } 
      } 
      bigramFrequencies.put(thisBigram, (double) thisBigramCount); 
     } 
    } 
    return bigramFrequencies; 
} 

Я использовать бинарный поиск, чтобы найти границы приговор, так что я не должен повторять при каждом появлении каждого слова и предложения. Но я не знаю, какие другие оптимизации можно было бы сделать. Должен ли я попробовать совершенно другой подход?

С помощью этого кода для каждой итерации внешней петли, которая является возмутительной, потребуется около 3 секунд.

Есть ли лучший способ сделать это?

ответ

0

Это то, что я буду делать. Сначала я бы разделил всю строку на управляемые маркеры, используя что-то вроде Scanner. Затем я попытаюсь сделать алгоритм, который эффективно определяет, является ли встречаемое слово уникальным или нет (как об использовании Hashset?). Каждый раз, когда встречается новое слово, начинается поток, который ищет биграмм с этим словом во всей строке (начиная с позиции сразу после первого вхождения слова), подсчитывает его появление и удаляет каждое вхождение этого слова из строка, когда она встречается с ней (это должно быть синхронизировано), так что дальнейшая обработка выполняется быстрее. Нити, которые подсчитывают вхождения слов, должны иметь более высокий приоритет, чем поток, ищущий новые слова.

Смежные вопросы