読者です 読者をやめる 読者になる 読者になる

広告/統計/アニメ/映画 等に関するブログ

広告/統計/アニメ/映画 等に関するブログ

【備忘録】Rでテキストマイニングする時に必要なテクニック

R 統計 広告

※2016/2/21時点での自分の最適解。
勉強中ゆえまだまだ未解決事項が残ってはいるものの、先ずはある程度のことまでできれば良しとしています。

テキストマイニングの為のツールは沢山あります。
商用ツールでも幾つかあるでしょうし、大学で導入されているSPSSにも入っていると思います。
個人が無料で出来るものとしては、

TTM: TinyTextMiner β versionKH Coder Index Pageが有名でしょう。
私もKHCoder愛用者です。

広告・マーケティング業界でテキストマイニングは、
・アンケートのフリーアンサー
・商品レビューサイトのレビューの分析
Twitter等、SNSの呟きの分析
などの需要がありますが、多くの分析は、単語の頻度や、共起語の頻度を出しているのが現状だと思います。
既存のツールでも既に充分応えられてはいますが、最近試してみて便利だな、と思ったのは、トピックモデルを使ったRのLDA(LDA:Latent Dirichlet Allocatoion)パッケージだったので、それを使う為に必要な手順をメモしておきたいと思います。

0)前提

Twitterのデータを何らかのサービスを使ってDLし、CSVファイルにしている。
・R(とRStudio)を入れている

の2点は終えた所からの準備とします。

1)mecabを入れて、IPAの辞書を変更する

形態素解析としてはmecabが一番便利だと思います。

MeCab: Yet Another Part-of-Speech and Morphological Analyzer

ダウンロードし、文字コードを環境に合わせて選んで解凍します。
辞書はデフォルトで入っているIPAを使います。*1
次に、mecabを使うためにPATHを通します。
mecabは MeCab\bin の中に入っているので、右クリック⇒プロパティで位置情報をコピペし、
マイコンピュータを右クリック⇒システムの詳細から下段のPATHを編集して、一番端っこまで移動して、「;」と先ほどのディレクトリ情報を貼り付けて終了です。*2

更に、この時注意が必要なのがIPAの辞書では未知語が「名詞、サ変接続」と設定されているために辞書を更新する必要がある点です。Twitterの呟きには記号が大変多いので、これをしておかないと後で困ります。

マイコンピュータで MeCabdic > ipadic まで移動し、「unk.def」というファイルをメモ帳等で開き、SYMBOLの所を以下のように変えます

SYMBOL,1283,1283,17585,名詞,サ変接続,*,*,*,*,*

SYMBOL,1283,1283,17585,記号,一般,*,*,*,*,*

コマンドプロンプトで MeCabdic > ipadic まで移動し

mecab-dict-index

と辞書を改めて憶えさせます。

2)RにRMeCab等を入れる

RMeCabのバージョンを間違えないように選択します

install - rmecab

Rで

  install.packages("RMeCab", repos = "http://rmecab.jp/R")

とするのが便利です。

3)LDAを入れる

RStudioを使っていれば普通にCRANからダウンロードできます

4)データの読み込み加工

準備が整ったので分析を始めます。
データの読込は、read.tableよりread.csvの方が文字コードの闇に巻き込まれないので便利です。
今回は、Twitterから「雪まつり」「雪像」という言葉が含まれたツイートをデータに使いました。

tw <- read.csv("yuki3.csv",header=T)
summary(tw)

summaryを使ってデータの状態を確認すると便利です。

このときデータフレームの列名が日本語の場合は英語にしておきます。

colnames(tw) <- c("Media","Date","Acount","url","honbun")

メディア          日付 タイトル                                                  URL
twitter 2016/2/4 0:00  DB_item http://twitter.com/DB_item/status/694898215582318594
                                                                                                                                                本文
1 超巨大な「ドラゴンボール」や「進撃の巨人」が待ってるぞ! 『さっぽろ雪まつり』は2016年2月5日開催だッ!! - ロケットニュース24 https://t.co/3xVdWbLtND

    Media          Date  Acount                                                  url
1 twitter 2016/2/4 0:00 DB_item http://twitter.com/DB_item/status/694898215582318594
                                                                                                                                              honbun
1 超巨大な「ドラゴンボール」や「進撃の巨人」が待ってるぞ! 『さっぽろ雪まつり』は2016年2月5日開催だッ!! - ロケットニュース24 https://t.co/3xVdWbLtNDっぽろ雪まつり』は2016年2月5日開催だッ!! - ロケットニュース24 https://t.co/3xVdWbLtND

5)RTやURLを削除する

ツイートデータにはだいたいリンクのURLだったり、公式RTのデータであれば、「RT @hogehoge」といった情報が一緒に入っている筈です。これらは、どんな話題がつぶやかれたのか?には、不要なので削除します。

tw$honbun <- gsub("^RT\\s@[0-9a-zA-Z\\._]*:\\s+","",tw$honbun)

RTで始まり、空白があり、@マークがあって英数字があってコロンで終わる部分を置換で削除してしまいます。
同様にURLも削除します。

tw$honbun <- gsub("https?://t.co/[0-9a-zA-Z\\._]*","",tw$honbun)

こちらのページを参考にさせて頂きました!

hiratake55.hatenablog.com

6)一度CSVファイルに書き出してまた読み込む

ここが現時点で謎のママなのですが、何故かそのままだと文字化けしてしまい、、、
一度CSVファイルに書き出してからまた読みなおしたデータフレームだと上手く行きました。

write.csv(tw,"tw_honbun_2.csv",quote=F)
tw2 <- read.csv("tw_honbun_2.csv",header=T)
colnames(tw2) <- c("ID","Media","Date","Acount","url","honbun")

ここはそもそも文字コード・改行コードの知識不足です。*3

7)docDFを使う

RMeCabと言えば、

Rによるテキストマイニング入門

Rによるテキストマイニング入門

 

 で、自分もこの本に触発されてRを知って勉強し始めたものでした。

しかし、この本には載っていない関数を使うのが便利です。
データフレームに対して、どの列にどの単語が出ているのか?のマトリックスを出します。

tw_docdf <- docDF(tw2,column="honbun",type=1)

このファイルの最初の2列を6行目まで見てみましょう

##         TERM POS1
## 1          ! 記号
## 2         !! 記号
## 3        !!! 記号
## 4      !!!!! 記号
## 5 !!!!!】... 記号
## 6     !!!\\( 記号

このように記号が沢山でてきます。mecabの辞書を変更していないと、ここで「記号」として貰えません。

ツイートの内容を理解するには、名詞・形容詞・動詞 辺りに情報を絞ると捉えやすくなります。

search_word <- c("名詞","形容詞","動詞")
tw_docdf_2 <- subset(tw_docdf,tw_docdf$POS1 %in% search_word)

頭の方の行は数字ばかりになるので、、、後ろから6行を6列めまで出すと、こんな感じになります

     TERM POS1 POS2 Row1 Row2 Row3
9827   艸 名詞 一般    0    0    0
9828 蜥蜴 名詞 一般    0    0    0
9829 蠢く 動詞 自立    0    0    0
9830 迸る 動詞 自立    0    0    0
9831 鍼灸 名詞 一般    0    0    0
9832 頷く 動詞 自立    0    0    0

この辺りはこちらのサイトを参考にさせて頂きました

Blog — RMeCabによる形態素解析とLDAによるトピック抽出

8)LDA用のデータを準備

移行は、ほぼほぼこの2つのサイトから

RでLDAの一例

http://rstudio-pubs-static.s3.amazonaws.com/16714_5b89bc4687994ff3b43c6e715ddadda1.html#R_LDA___

qiita.com

事前に格納する為のオブジェクトが必要なのが通常のRとは違います。
先ず、リストのオブジェクトを作り、その中に頻度表のデータを入れます。
4列目から入れているのは、頻度データが4列目から入っているためです

また、それとは別に、単語のリストもオブジェクトを作ります。

doc <- list()
for (i in c(4:ncol(tw_docdf_2))) {
  d <- tw_docdf_2[,i]
  doci-3 <- rbind(as.integer*4[d>0]-1),as.integer(d[d>0]))
}
vcab <- tw_docdf_2[,1]

9)LDAを実行

LDAパッケージのギブズサンプリングを行います。*5
この「n」に入れる数字で、トピックスの数何単語の組み合わせのセットにするかを決められます。

n <- 10
ldaret <- lda.collapsed.gibbs.sampler(doc,n,vcab,1000,0.1,0.001)
summary(ldaret)

トピックスを10程度、見つけてくれました。

              Length Class  Mode   
assignments     50   -none- list   
topics        6430   -none- numeric
topic_sums      10   -none- numeric
document_sums  500   -none- numeric
<NA>             0   -none- NULL   
<NA>             0   -none- NULL   
<NA>             0   -none- NULL   
<NA>             0   -none- NULL   
<NA>             0   -none- NULL   
<NA>             0   -none- NULL

10)可視化の準備1

この辺、まだ理解が追いついていませんが、各トピックスから10ワードを抜き出す設定にしてみます

k_words <- 10
top.words <- top.topic.words(ldaret$topics,k_words,by.score=TRUE)

例えば、トップワードの一列目を抜き出してみます

(top.words[,1])

こんな感じです ↓

 [1] "新幹線"                     "凄い"                       "プロジェクションマッピング"
 [4] "まつる"                     "すぎる"                     "POP"                       
 [7] "防弾"                       "団"                         "少年"                      
[10] "FESTIVAL" 

10個位抜き出すと、「新幹線」の「凄い」「プロジェクションマッピング」があった、という内容と、残りはちょっとわかりませんが、そんな話題があった、ということがわかります。

11)可視化の準備2

次に、グラフにするときに、何ツイートを抜き出すか決めます。
例えば、こちらでは、「20」に設定しました。

N <- 20
topic.proportions <- t(ldaret$document_sums)/colSums(ldaret$document_sums)
topic.proportions <- topic.proportions[1:N,]
topic.proportions[is.na(topic.proportions)] <- 1/n

こうすることで、抽出された10のトピックスが、20個のツイートのうち、どれ位の割合でどう分布しているのか?を見ることができます。

12)可視化の準備3

ggplotで可視化するためにreshape2パッケージでmeltします。

topic.proportions.df <- melt(cbind(data.frame(topic.proportions),document=factor(1:N)),variable.name="topic", id.vars = "document")

こんなデータ構造です。document

  document                                                                          topic
1        1 新幹線.凄い.プロジェクションマッピング.まつる.すぎる.POP.防弾.団.少年.FESTIVAL
2        2 新幹線.凄い.プロジェクションマッピング.まつる.すぎる.POP.防弾.団.少年.FESTIVAL
3        3 新幹線.凄い.プロジェクションマッピング.まつる.すぎる.POP.防弾.団.少年.FESTIVAL
4        4 新幹線.凄い.プロジェクションマッピング.まつる.すぎる.POP.防弾.団.少年.FESTIVAL
5        5 新幹線.凄い.プロジェクションマッピング.まつる.すぎる.POP.防弾.団.少年.FESTIVAL
6        6 新幹線.凄い.プロジェクションマッピング.まつる.すぎる.POP.防弾.団.少年.FESTIVAL
      value
1 0.3809524
2 0.8333333
3 0.0000000
4 0.0000000
5 0.0000000
6 0.0000000

topicの一つめが、docimen1にどれ位含まれているか?を意味しているようです。
docmentになっているのは、元々ツイート1つ1つに対して使うというよりも、複数の書類(文書)の中に、共通したトピックスがどれ位みられるか?を調べるものなので、今回のように140文字のツイートに対して使うのは、やや不適切な使い方なのかもしれませんね。

12)ggplot2で可視化

後はいつもと同じですが、ツイート(document)毎に色分けをしてグラフ化。
他のサイトではfacet_wrapをしてマトリックスにしていますが、今回は20ツイートも選んでいるので入りきらなくなってしまいますのでパス

g <- ggplot(topic.proportions.df,aes(x=topic,y=value,fill=document))
g <- g + theme_gray(base_family="Japan1GothicBBB")
g <- g + geom_bar(stat = "identity",position = "dodge",)
#g <- g + facet_wrap(~document,ncol=N)
g <- g + coord_flip()
plot(g)

また、PDF等で保存する時に文字化けを防ぐために、この段階で、フォントを指定しておくのがggplotにおけるポイントです。

f:id:yyhhyy:20160221183928p:plain

これだけでも何となくわかると思いますが、
ラブライブ」だとか「三太郎」(auのやつですかね?)だとか、「行くよ!」と言うようなツイートも結構あったのだということが見て取れます。

13)具体的なツイートを検索する

10単語ではわかるところ、わからないところがあるので、元々のファイルをテキストエディタなりExcelなりで開いて、キーワードを検索してみます。

例えば、「オーストラリア」「すぎる」というツイートは、

 のツイートだとわかります。

結構シェアされていますね。

ドラゴンボール」や「進撃の巨人」は、

 のニュース記事のシェアだとわかります。

 「熱気」は、なんだろう?と思うと

 ということのようです。
キャラクターやアイドルというコアなファンが居るコンテンツはTwitterではシェアされやすいので、公式RTを含むようにすると多くヒットする傾向にあります。

その他、「行く」「寒い」などは、一つの呟きのシェアではありませんが、幾つか検索すると、「やっぱ寒いー」だったり「行ったよー」「行きたいー」などのツイートがありました。

14)補講1 公式RTの除外

公式RTを外して分析する場合は、grep公式RTを含む行名を取得し、
その行を外したデータを作り直します。

rt_list <- grep("^RT\\s@[0-9a-zA-Z\\._]*:\\s+",tw[,1])
head(rt_list)
tw <-tw[-(rt_list),]

15)補講2 そもそも論

Twitterは、ゴミツイートが多く今回は少なかったものの変なbotやらステマアカウントがあるのでもっと事前に除外しないといけないことが多いです。
また、もっと抽出量が少ないうちは、目視で人間の目で見て分析するのが、一番発見が多いものです。

--------------------------

参考書

本来はちゃんとアルゴリズムを勉強してから使わないと、きっと落とし穴にハマるのですが、今のところ上手く検出できているようなので取り急ぎは満足していますが、いずれは勉強したいところ。。。

この2冊を推薦しているサイトが多いので、これから頑張ります。

トピックモデル (機械学習プロフェッショナルシリーズ)

トピックモデル (機械学習プロフェッショナルシリーズ)

 

 

トピックモデルによる統計的潜在意味解析 (自然言語処理シリーズ)

トピックモデルによる統計的潜在意味解析 (自然言語処理シリーズ)

 

 

*1:今後もっと勉強したいところ

*2:再起動した方が無難です

*3:因みにWinでmecabutf-8、RStudioもutf8に、という環境ですが、write.csvをしたcsvファイルはSHIFT-JISになっているようです。。。

*4:1:length(d

*5:本当はこのアルゴリズムを先に勉強すべきなのですが。。。