расстояние по косинусу

1

Мне даны два документа, и меня просят вычислить частоту появления каждого слова в документах. Например, в doc1 и doc2 слово "CAT" появилось дважды в каждом, тогда оно появилось 4 раза, и мне нужно вычислить частоту его появления.

Через некоторые поисковые запросы Google за последние три ночи я нашел отличный алгоритм, называемый сходством косинусов. Теперь я понимаю, как это работает.

Но я не знаю, как реализовать его на Java. Как преобразовать слова в векторы?

Предположим, что мой вклад - "сколько деревянных патронов патрона из дерева можно забить деревом", как я мог преобразовать слова в n векторное пространство? Я сначала делаю массив слов, а затем перебираю массив с помощью переменной count, чтобы узнать, сколько раз это слово произошло? Но не означает ли это, что нам нужно как минимум n счетных переменных?

Большое вам спасибо за то, что помогли мне понять это

  • 0
    Итак, вы хотите посчитать частоты слов из строки со встроенными переводами строки и другими «несловными» символами? И я полагаю, что апостроф допускается как символ слова?
  • 0
    @Bohemian Богемский спасибо за ваш ответ! Нет, только слова или буквенно-цифровые символы могут быть засчитаны как слова :)
Показать ещё 4 комментария
Теги:
cosine-similarity

3 ответа

0
Лучший ответ

Да, это правильно. Вам понадобится столько компонентов, сколько в ваших двух документах будут уникальными словами, если вы хотите учитывать частоту каждого слова.

Один простой способ сделать это в Java - создать HashMap, со String ключами и Integer значениями. Просто просмотрите список слов, как они появляются в документе, и добавьте его в соответствующую запись в HashMap. В итоге вы получите значения как значения против слов в качестве ключей. Убедитесь, что при добавлении одного из них, если запись не существует, вы инициализируете ее до 1.

Подробнее о псевдокоде:

for word in doc1
    if (!vector1.has(word)) {vector1.put(word, 0);}
    if (!vector2.has(word)) {vector2.put(word, 0);}
    vector1.put(word, vector1.get(word) + 1);
done
same loop for doc2, with the last line changed to vector2

Теперь у вас есть как векторы с теми же словами, что и ключи, и подсчеты в соответствующих документах. Затем вы можете использовать любого, чтобы пройти по словам:

dotp = 0; v1sq = 0; v2sq = 0
for word in vector1
    dotp = dotp + vector1.get(word) * vector2.get(word)
    v1sq = v1sq + vector1.get(word) * the-same-thing
    v2sq = the-same-same-thing
done
similarity = dotp / sqrt(v1sq * v2sq)

Вот ты где! Просто выработайте часть Java.

  • 0
    но это не значит, что если вам дают два документа, говорят, что в документе doc1 есть 1 тыс. слов, а в документе doc2 (doc1) ^ 2 слова, то время, которое потребуется для вычисления аналогичных слов, будет эквивалентно вычислению doc1 * doc1 * doc1, которое даже хуже, чем вычисление квадратичного времени! или, может быть, я ошибаюсь, потому что для каждого слова вам нужно просмотреть все два документа! или я неправильно истолковал то, что ты сказал`
  • 0
    Если вы говорите об A . B / |A| |B| формула, это займет O(n) время, чтобы вычислить это, где n - количество уникальных слов в обоих документах вместе.
Показать ещё 2 комментария
1

Удерживайте результаты в виде Map<String, Integer> и используйте String#split() для разделения ввода на слова.

вам понадобится только одна строка кода после того, как вы прочтете текст в строку:

Map<String, Integer> frequencies = Arrays
    .stream(text.toLowerCase().split("[^a-z']+"))
    .collect(Collectors.groupingBy(s -> s, Collectors.counting());
0

Я провел потрясающую серию видеороликов MIT: Модели вычислений, расстояние до документа. И я нашел эту проблему там.

Поэтому я написал код Java, чтобы найти расстояние между двумя документами, где документ - не что иное, как слова, разделенные пробелами.

import java.util.HashMap;
import java.util.Scanner;

public class document_distance {

//print the string array made from document
public static void printDoc(String[] doc) {
    System.out.println("=====printing doc words ====");
    int len = doc.length;
    for( int i=0; i<len; i++ )  {
        System.out.print(doc[i]+" ");
    }
    System.out.println();
}

public static void printMap(HashMap<String, Integer> dict) {
    System.out.println("=====printing dictionary (key,value) ====");
    for(String key: dict.keySet()) {
        System.out.println(key+" ->"+dict.get(key));
    }
}

public static void main(String[] args) {

    Scanner sc = new Scanner(System.in);
    String doc1[] = sc.nextLine().split(" ");
    String doc2[] = sc.nextLine().split(" ");

    //print both documents to verify that they are saved correctly!
    printDoc(doc1);
    printDoc(doc2);

    //create two dictionaries with keys as words and values as count of that word!
    HashMap<String, Integer> dict1 = new HashMap<String, Integer>();
    HashMap<String, Integer> dict2 = new HashMap<String, Integer>();

    //update counts for doc1 both dictionaries
    for(int i=0; i<doc1.length ;i++) {
        if(!dict1.containsKey(doc1[i])) { //word is not in dict1 yet
            dict1.put(doc1[i], 1);
        }
        else if(dict1.containsKey(doc1[i])) { //word is in dict1 
            dict1.put(doc1[i], dict1.get(doc1[i]) + 1);
        }

        if(!dict2.containsKey(doc1[i])) { //word is not in dict2 yet
            dict2.put(doc1[i], 0);
        }


    }

    //update counts for doc1 both dictionaries
    for(int i=0; i<doc2.length ;i++) {
        if(!dict2.containsKey(doc2[i])) { //word is not in dict2 yet
            dict2.put(doc2[i], 1);
        }
        else if(dict2.containsKey(doc2[i])) { //word is in dict2
            dict2.put(doc2[i], dict2.get(doc2[i]) + 1);
        }

        if(!dict1.containsKey(doc2[i])) { //word is not in dict1
            dict1.put(doc2[i], 0);
        }


    }
    //print dictionaries
    printMap(dict1);
    printMap(dict2);

    int dotProduct =0;
    int doc1sq = 0;
    int doc2sq = 0;
    for(int i=0; i<doc1.length ;i++) {
        dotProduct = dotProduct + (dict1.get(doc1[i])) * (dict2.get(doc1[i]));
        doc1sq = doc1sq +  (dict1.get(doc1[i])) *  (dict1.get(doc1[i]));
        doc2sq = doc2sq +  (dict2.get(doc1[i])) *  (dict2.get(doc1[i]));    
    }

    double similarity = dotProduct / Math.sqrt(doc1sq*doc2sq);
    System.out.print("similarity = "+ similarity);

}

}
  • 0
    чувак, это круто, как будто ты буквально вернул мое любопытство к жизни.
  • 0
    Я рад, что это помогло :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню