web-dev-qa-db-ja.com

Rテキスト分析によるステミング

私はTMパッケージで多くの分析を行っています。私の最大の問題の1つは、ステミングとステミングのような変換に関連しています。

私がいくつかの会計関連の用語を持っているとしましょう(私はスペルの問題を知っています)。
ステミング後、次のようになります。

accounts   -> account  
account    -> account  
accounting -> account  
acounting  -> acount  
acount     -> acount  
acounts    -> acount  
accounnt   -> accounnt  

結果:3つの用語(アカウント、アカウント、アカウント)。これらはすべて同じ用語に関連しているため、1つ(アカウント)が好きでした。

1) スペルを修正することは可能ですが、私はRでそれを試みたことがありません。それも可能ですか?

2) もう1つのオプションは、参照リスト、つまりaccount =(accounts、account、accounting、acounting、acount、acounts、accounnt)を作成し、すべての出現箇所をマスター用語に置き換えることです。 Rでこれをどのように行うのですか?

繰り返しになりますが、どんな助け/提案も大歓迎です。

12
RUser

同義語のリストを設定し、それらの値を置き換えることができます。例えば

synonyms <- list(
    list(Word="account", syns=c("acount", "accounnt"))
)

これは、「acount」と「accounnt」を「account」に置き換えたいことを示しています(ステミング後にこれを行っていると想定しています)。それでは、テストデータを作成しましょう。

raw<-c("accounts", "account", "accounting", "acounting", 
     "acount", "acounts", "accounnt")

次に、リスト内の単語を主要な同義語に置き換える変換関数を定義しましょう。

library(tm)
replaceSynonyms <- content_transformer(function(x, syn=NULL) { 
    Reduce(function(a,b) {
        gsub(paste0("\\b(", paste(b$syns, collapse="|"),")\\b"), b$Word, a)}, syn, x)   
})

ここでは、content_transformer関数を使用してカスタム変換を定義します。そして基本的には、gsubを実行して各単語を置き換えます。これをコーパスで使用できます

tm <- Corpus(VectorSource(raw))
tm <- tm_map(tm, stemDocument)
tm <- tm_map(tm, replaceSynonyms, synonyms)
inspect(tm)

そして、これらすべての値が必要に応じて「アカウント」に変換されていることがわかります。他の同義語を追加するには、メインのsynonymsリストにリストを追加するだけです。各サブリストには、「Word」と「syns」という名前を付ける必要があります。

13
MrFlick

フリック氏は質問2に答えました。質問1に答えてアプローチしています。

これは、既知のWordデータベース(DICTIONARY from qdapDictionaries)のバイナリ検索を使用するアプローチです。バイナリルックアップは確かに遅いですが、置換についていくつかの仮定を行う場合(文字数の違いの範囲など)。したがって、基本的な考え方は次のとおりです。

  1. Corpusbag_o_wordsを使用して、qdapをユニークな単語の袋に変えます
  2. それらの単語を辞書(qdapDictionaries'DICTIONARYデータセット)で調べて、match [.____を使用して認識できない単語を見つけます。]
    • ステップ2のこれらのmissesは、ルックアップするものになります
  3. 後でncharを使用して大きな違いをなくすために、辞書内の単語の文字数を決定します
  4. missesの各要素をループ(sapply)で実行し、次の手順を実行します。
    a。 tm::stemDocumentを使用してmissesから各要素をステム処理します
    b。 ncharを使用して、文字数を決定し、その範囲内にない文字を辞書から削除します。
    c。 agrepmax.distanceを使用して、辞書からより多くの単語を削除します
    d。バイナリルックアップ(リバースエンジニアリングagrep)を使用して、欠落した要素に最も近い辞書から単語を決定します[これはqdap:::Ldistと呼ばれるqdapからエクスポートされない関数であることに注意してください]
  5. 結果は、gsubbingに使用できる名前付きベクトルです。
  6. tm_mapをカスタムのtmフレーバーのgsub関数とともに使用して、単語を置き換えます
  7. tm_mapstemDocumentでステミングを行います

これがコードです。私はあなたが提供した単語といくつかのランダムな単語を使用して偽のCorpusを作成し、これを最初から最後まで行う方法を示しました。 rangeに提供されているsapplymax.distanceで遊ぶことができます。これらを緩くすると検索が遅くなりますが、締めすぎると間違いを犯しやすくなります。これは実際には一般的な意味でのスペル修正の答えではありませんが、とにかくステミングしていたのでここで機能します。 Aspell パッケージがありますが、これまで使用したことがありません。

terms <- c("accounts", "account", "accounting", "acounting", "acount", "acounts", "accounnt")

library(tm); library(qdap)

fake_text <- unlist(lapply(terms, function(x) {
    paste(sample(c(x, sample(DICTIONARY[[1]], sample(1:5, 1)))), collapse=" ")
}))

fake_text

myCorp <- Corpus(VectorSource(fake_text))
terms2 <- unique(bag_o_words(as.data.frame(myCorp)[[2]]))
misses <- terms2[is.na(match(terms2, DICTIONARY[[1]]))]

chars <- nchar(DICTIONARY[[1]])

replacements <- sapply(misses, function(x, range = 3, max.distance = .2) {
    x <- stemDocument(x)
    wchar <- nchar(x)
    dict <- DICTIONARY[[1]][chars >= (wchar - range) & chars <= (wchar + range)]
    dict <- dict[agrep(x, dict, max.distance=max.distance)]
    names(which.min(sapply(dict, qdap:::Ldist, x)))
})

replacer <- content_transformer(function(x) { 
    mgsub(names(replacements), replacements, x, ignore.case = FALSE, fixed = FALSE)
})

myCorp <- tm_map(myCorp, replacer)
inspect(myCorp <- tm_map(myCorp, stemDocument))
8
Tyler Rinker

この質問から、qdapパッケージのスペルチェックを書こうと思いました。ここで役立つかもしれないインタラクティブなバージョンがあります。 qdap >= version 2.1.1で入手できます。つまり、現時点では開発バージョンが必要です。インストールする手順は次のとおりです。

library(devtools)
install_github("qdapDictionaries", "trinker")
install_github("qdap", "trinker")
library(tm); library(qdap)

##説明したようにCorpusを再作成します。

terms <- c("accounts", "account", "accounting", "acounting", "acount", "acounts", "accounnt")

fake_text <- unlist(lapply(terms, function(x) {
    paste(sample(c(x, sample(DICTIONARY[[1]], sample(1:5, 1)))), collapse=" ")
}))

fake_text

inspect(myCorp <- Corpus(VectorSource(fake_text)))

##インタラクティブなスペルチェッカー(check_spelling_interactive

m <- check_spelling_interactive(as.data.frame(myCorp)[[2]])
preprocessed(m)
inspect(myCorp <- tm_map(myCorp, correct(m)))

correct関数は、check_spelling_interactiveの出力からクロージャ関数を取得するだけで、新しいテキスト文字列に「修正」を適用できます。

7
Tyler Rinker