2015-10-13 43 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的帖子標記爲正確的答案,因爲這是迄今爲止最好和最可行的做事方式(我知道)。

相關問題