我有两份文件,我被要求计算文件中每个单词出现的频率。例如,在doc1和doc2中,单词“CAT”每次出现两次,然后它总共出现了4次,我需要计算它出现的频率。
通过过去三晚的谷歌搜索,我找到了一种称为余弦相似度的优秀算法。我现在明白它是如何工作的。
但我不知道如何在Java中实现它。我应该如何将单词转换为向量?
假设我的输入是“多少木头夹头的土拨鼠可以扔掉木头”我怎么能将这些单词转换成n向量空间?我首先创建一个单词数组,然后使用count变量遍历数组,看看这个单词出现了多少次?但那不就意味着我们至少需要n个计数变量吗?
非常感谢你帮我解决这个问题
答案 0 :(得分:1)
将结果保持为Map<String, Integer>
,并使用String#split()
将输入分隔为单词。
在将文本读入字符串后,您只需要一行代码:
Map<String, Integer> frequencies = Arrays
.stream(text.toLowerCase().split("[^a-z']+"))
.collect(Collectors.groupingBy(s -> s, Collectors.counting());
答案 1 :(得分:1)
我正在看麻省理工学院的精彩视频系列:Models of Computation, Document Distance。我在那里发现了这个问题。
所以我写了一个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);
}
}
答案 2 :(得分: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部分。