2015-10-13 42 views
9

我试图找到同时出现在多个文档中的单词。以相同的方式处理由空格分隔的单词

让我们举一个例子。

doc1: "this is a document about milkyway" 
doc2: "milky way is huge" 

正如你可以看到上述2个文件,字“银河”是发生在两个文档但在第二文档术语“银河”是由一个空间和在第一DOC中分离它不是。

我做以下,以获得文档词矩阵R.

library(tm) 
tmp.text <- data.frame(rbind(doc1, doc2)) 
tmp.corpus <- Corpus(DataframeSource(tmp.text)) 
tmpDTM <- TermDocumentMatrix(tmp.corpus, control = list(tolower = T, removeNumbers = T, removePunctuation = TRUE,stopwords = TRUE,wordLengths = c(2, Inf))) 
tmp.df <- as.data.frame(as.matrix(tmpDTM)) 
tmp.df 

     1 2 
document 1 0 
huge  0 1 
milky 0 1 
milkyway 1 0 
way  0 1 

期限milkyway只出现在第一文档按上述矩阵。

我希望能够在上述矩阵中的术语“milkyway”的文档中都获得1。这只是一个例子。我需要为许多文件做这件事。最终,我希望能够以类似的方式对待这些词(“银河”&“银河系”)。

编辑1:

我不能强迫得到这样的方式,对于任何讲它正试图寻找它不应该仅仅寻找那些单词作为计算术语文档矩阵单词中的字符串,但也在字符串内?例如,一个术语是milky,并且有一个文档this is milkyway,因此这里当前的milky不会在此文档中出现,但是如果算法在字符串内查找有问题的单词,它还会在字符串milkyway内找到字milky,那样字milkyway将被计入我的两份文件(前面的例子)。

编辑2:

最终我想能够计算出文档之间的相似性余弦指数。

+0

也许删除空格,然后使用正则表达式? – zx8754

+0

您是否只需要为“银河系”或其他人执行此操作?你喜欢他们都是'银河'吗? –

+0

@ sebastian-c我需要为多个单词做这件事。我更喜欢以某种方式成为“银河”。可能会有像“每天”和“每一天”的情况。在这种情况下,我宁愿他们是“每天”。 – user3664020

回答

0

通过插入“\\ s?”,您可以使用正则表达式匹配单词的每个可能的分割。搜索词中的每个字符之间。如果你只想要特定的分割,你只需将它插入这些地方。以下代码通过插入“\\ s?”为搜索项生成正则表达式模式。每个角色之间。 grep返回模式匹配位置的索引,但可以交换为其他正则表达式函数。

docs <- c("this is a document about milkyway", "milky way is huge") 
search_terms <- c("milkyway", "document") 
pattern_fix <- sapply(strsplit(search_terms, split = NULL), paste0, collapse = "\\s?") 
sapply(pattern_fix, grep, docs) 

$`m\\s?i\\s?l\\s?k\\s?y\\s?w\\s?a\\s?y` 
[1] 1 2 

$`d\\s?o\\s?c\\s?u\\s?m\\s?e\\s?n\\s?t` 
[1] 1 

编辑:

要搜索所有的话,你可以只使用tmp.df的名字在你的脚本在我的解决方案的SEARCH_TERMS。

doc1 <- "this is a document about milkyway" 
doc2 <- "milky way is huge" 

library(tm) 
tmp.text<-data.frame(rbind(doc1,doc2)) 
tmp.corpus<-Corpus(DataframeSource(tmp.text)) 
tmpDTM<-TermDocumentMatrix(tmp.corpus, control= list(tolower = T, removeNumbers = T, removePunctuation = TRUE,stopwords = TRUE,wordLengths = c(2, Inf))) 
tmp.df<-as.data.frame(as.matrix(tmpDTM)) 
tmp.df 

search_terms <- row.names(tmp.df) 
pattern_fix <- sapply(strsplit(search_terms, split = NULL), paste0, collapse = "\\s?") 
names(pattern_fix) <- search_terms 
word_count <- sapply(pattern_fix, grep, tmp.text[[1]]) 
h_table <- sapply(word_count, function(x) table(factor(x, levels = 1:nrow(tmp.text)))) #horizontal table 
v_table <- t(h_table) #vertical table (like tmp.df) 
v_table 

     1 2 
document 1 0 
huge  0 1 
milky 1 1 
milkyway 1 1 
way  1 1 
+0

感谢努力。但是你的解决方案要求我明确提到我想要匹配的术语,而这些术语我事先不知道。如果这有助于您提出更好的解决方案,请参阅我的编辑1和编辑2。 – user3664020

+0

看我的编辑。可能有更好的方法,但这至少适用于这个简短的例子。 – JohannesNE

1

您需要将文档转换为原始字的袋子前表示。当一个基元词与一组词相匹配时。原始词也可以在语料库中。

例如:

milkyway -> {milky, milky way, milkyway} 
economy -> {economics, economy} 
sport -> {soccer, football, basket ball, basket, NFL, NBA} 

您可以建立这样的字典,这两个同义词词典和像莱文施泰因将完成同义词词典一个编辑距离计算余弦距离之前。

计算'运动'键更涉及。

0

这是一个解决方案,不需要预设的单词列表,但通过在相邻单词之间没有分隔符的情况下将文本标记为bigrams来执行分隔,然后在unigram标记化中查找匹配。然后保存这些文件,然后在文本中用分隔的版本替换。

这意味着不需要预先设置的列表,但只有那些在文本中具有等同分析版本的未解析的列表。请注意,这可能会产生错误肯定,例如“berated”和“be rated”,它们可能不是同一对的发生,而是与第一项中的有效单元不同,与第二项中的等效串联二元数不同。 (这一特定问题没有完美的解决方案存在。)

该解决方案需要quanteda包文本分析和stringi包矢量化正则表达式替换。

# original example 
myTexts <- c(doc1 = "this is a document about milkyway", doc2 = "milky way is huge") 

require(quanteda) 

unparseMatches <- function(texts) { 
    # tokenize all texts 
    toks <- quanteda::tokenize(toLower(texts), simplify = TRUE) 
    # tokenize bigrams 
    toks2 <- quanteda::ngrams(toks, 2, concatenator = " ") 
    # find out which compressed pairs exist already compressed in original tokens 
    compoundTokens <- toks2[which(gsub(" ", "", toks2) %in% toks)] 
    # vectorized replacement and return 
    result <- stringi::stri_replace_all_fixed(texts, gsub(" ", "", compoundTokens), compoundTokens, vectorize_all = FALSE) 
    # because stringi strips names 
    names(result) <- names(texts) 
    result 
} 

unparseMatches(myTexts) 
##         doc1         doc2 
## "this is a document about milky way"     "milky way is huge" 
quanteda::dfm(unparseMatches(myTexts), verbose = FALSE) 
## Document-feature matrix of: 2 documents, 8 features. 
## 2 x 8 sparse Matrix of class "dfmSparse" 
##  features 
## docs this is a document about milky way huge 
## doc1 1 1 1  1  1  1 1 0 
## doc1 0 1 0  0  0  1 1 1 


# another test, with two sets of phrases that need to be unparsed 
testText2 <- c(doc3 = "This is a super duper data set about the milky way.", 
       doc4 = "And here is another superduper dataset about the milkyway.") 
unparseMatches(testText2) 
##               doc3               doc4 
##   "This is a super duper data set about the milky way." "And here is another super duper data set about the milky way." 
(myDfm <- dfm(unparseMatches(testText2), verbose = FALSE)) 
## Document-feature matrix of: 2 documents, 14 features. 
## 2 x 14 sparse Matrix of class "dfmSparse" 
##  features 
## docs this is a super duper data set about the milky way and here another 
## doc3 1 1 1  1  1 1 1  1 1  1 1 0 0  0 
## doc4 0 1 0  1  1 1 1  1 1  1 1 1 1  1 

quanteda也可以做类似的计算,如余弦距离:

quanteda::similarity(myDfm, "doc3", margin = "documents", method = "cosine") 
##  doc4 <NA> 
## 0.7833  NA 

我不知道的NA是什么 - 它似乎是错误的输出,当有刚一个文档与一个双文档集进行比较。 (我会尽快解决这个问题,但结果仍然是正确的。)

0

肯已经指出:(这一特定问题没有完美的解决方案存在)

对于所有我知道这是绝对正确的,并且受到许多关于文本挖掘的教科书和期刊的支持 - 通常在前几段中。

在我的研究中,我依靠已经准备好的数据集,如the „Deutscher Wortschatz“ project.他们已经完成了艰苦的工作,并提出了同义词,反义词,多义词术语等高质量列表。通过肥皂提供接口访问。一种英语语言数据库是Wordnet,e.g ..

如果你不想使用预先计算的设定或无法负担得起,我建议你用amirouche的做法和原始字表示去。用词建立它们是乏味和劳动密集型的,但却是最可行的方法。

我想到的其他方法肯定是更复杂的方法。请看G. Heyer,U. Quasthoff和T.的“Text Mining,Wissensrohstoff Text”中的其他答案或最新的方法。Wittig通过(1)识别特征(索引术语),(2)创建术语句子矩阵和选择用于计算术语术语矩阵的权重,(3)选择相似性测量并在你的术语矩阵上运行它,最后(4)挑选并运行一个聚类算法。

我建议你将amirouche的帖子标记为正确的答案,因为这是迄今为止最好和最可行的做事方式(我知道)。

相关问题