Мне даны два документа, и меня просят вычислить частоту появления каждого слова в документах. Например, в doc1 и doc2 слово "CAT" появилось дважды в каждом, тогда оно появилось 4 раза, и мне нужно вычислить частоту его появления.
Через некоторые поисковые запросы Google за последние три ночи я нашел отличный алгоритм, называемый сходством косинусов. Теперь я понимаю, как это работает.
Но я не знаю, как реализовать его на Java. Как преобразовать слова в векторы?
Предположим, что мой вклад - "сколько деревянных патронов патрона из дерева можно забить деревом", как я мог преобразовать слова в n векторное пространство? Я сначала делаю массив слов, а затем перебираю массив с помощью переменной count, чтобы узнать, сколько раз это слово произошло? Но не означает ли это, что нам нужно как минимум n счетных переменных?
Большое вам спасибо за то, что помогли мне понять это
Да, это правильно. Вам понадобится столько компонентов, сколько в ваших двух документах будут уникальными словами, если вы хотите учитывать частоту каждого слова.
Один простой способ сделать это в 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.
A . B / |A| |B|
формула, это займет O(n)
время, чтобы вычислить это, где n
- количество уникальных слов в обоих документах вместе.
Удерживайте результаты в виде Map<String, Integer>
и используйте String#split()
для разделения ввода на слова.
вам понадобится только одна строка кода после того, как вы прочтете текст в строку:
Map<String, Integer> frequencies = Arrays
.stream(text.toLowerCase().split("[^a-z']+"))
.collect(Collectors.groupingBy(s -> s, Collectors.counting());
Я провел потрясающую серию видеороликов 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);
}
}