からっぽのしょこ

読んだら書く!書いたら読む!読書読読書読書♪同じ事は二度調べ(たく)ない

koRpus(TreeTagger)の形態素解析結果をRMeCab::docDF()仕様に変換する

はじめに

 英文(多言語)形態素解析器TreeTaggerをR言語で利用するためのパッケージkoRpusの出力を、RMeCab::docDF()の出力の仕様に加工します。


ファイル単位の出力をdocDF()仕様に変換

・設定

## 利用パッケージ
# TreeTagger
library(koRpus)
library(koRpus.lang.en)

# MeCab
library(RMeCab)

# その他処理
library(dplyr)
library(readr)

 利用するパッケージを読み込みます。

# TreeTaggerを利用するための設定
set.kRp.env(TT.cmd = "C:\\TreeTagger\\bin\\tag-english.bat", lang = "en")

 TreeTaggerを使うための設定です。

・英文形態素解析

 英語テキストを単語に分解して、各単語の品詞情報を取得します。

# フォルダ名を指定
folder_name <- "text_data"

# ファイル名を指定
file_name <- "wonderful_world.txt"

 ファイルパス用に、ディレクトリ名とテキストファイル名を指定します。テキスト名は後でも使うので、ここでは分けて指定しています。

# TreeTaggerによる英文形態素解析
res_tt <- taggedText(treetag(paste(folder_name, file_name, sep = "/"))) %>% 
  as_tibble()

 ファイルパスを指定して、英文形態素解析を行います。

tail(res_tt)
## # A tibble: 6 x 11
##   doc_id token tag   lemma  lttr wclass      desc  stop  stem    idx sntc 
##   <fct>  <chr> <fct> <chr> <dbl> <fct>       <lgl> <lgl> <lgl> <int> <lgl>
## 1 <NA>   A     DT    a         1 determiner  NA    NA    NA      282 NA   
## 2 <NA>   world NN    world     5 noun        NA    NA    NA      283 NA   
## 3 <NA>   for   IN    for       3 preposition NA    NA    NA      284 NA   
## 4 <NA>   you   PP    you       3 pronoun     NA    NA    NA      285 NA   
## 5 <NA>   and   CC    and       3 conjunction NA    NA    NA      286 NA   
## 6 <NA>   me    PP    me        2 pronoun     NA    NA    NA      287 NA

 出力はこんな感じです。

 ここから必要な列を取り出します。

# 必要なデータを抽出
tt_data <- res_tt %>% 
  select(lemma, wclass, tag) %>% # 必要な列を取り出す
  count(lemma, wclass, tag) %>% # 単語の出現頻度を集計
  rename(TERM = lemma, !!file_name := n) %>% # RMeCab仕様に列名を変更
  arrange(TERM) # 昇順に並べ替え

 この例では、lemma(単語の原型)、wclass(品詞)、tag(品詞コード)を用います。

 count()で頻度列を作ります。列名はnになります。

 列名をRMeCab::docDF()仕様にするために、単語列をTERM、頻度列をファイル名にrename()で変更します。

tail(tt_data)
## # A tibble: 6 x 4
##   TERM      wclass      tag   wonderful_world.txt
##   <chr>     <fct>       <fct>               <int>
## 1 what      pronoun     WP                      1
## 2 with      preposition IN                      2
## 3 wonderful adjective   JJ                      4
## 4 world     noun        NN                      4
## 5 you       pronoun     PP                     18
## 6 your      pronoun     PP$                     5

 こんな感じになります。

・品詞情報の対応表の準備

 形態素解析の結果は当然英語の品詞情報なので、日本語の品詞情報に変更する必要があります。そのための対応表(未完成)を読み込みます。対応表のデータは私のGitHubレポジトリから取得してください。

github.com


# 対応表を読み込む
pos_data <- read_csv(
  "table_data/PoS_data_utf8.csv", 
  col_types = cols(
    tag = col_factor(), 
    wclass = col_factor()
  )
)

 対応表データのファイルパスを指定して、readr::read_csv()で読み込みます。(一応品詞情報を因子型に変更していますが、特に意味があるのかないのか…?)

head(pos_data)
## # A tibble: 6 x 7
##   tag   wclass    POS1   POS2  Description         品詞          Example        
##   <fct> <fct>     <chr>  <chr> <chr>               <chr>         <chr>          
## 1 CC    conjunct~ 接続詞 <NA>  Coordinating conju~ 等位接続詞    and, but, or, &
## 2 CD    number    名詞   数    Cardinal number     基数          1, three       
## 3 DT    determin~ <NA>   <NA>  Determiner          限定詞        the            
## 4 EX    existent~ <NA>   <NA>  existential there   存在文のThere there is       
## 5 FW    foreign   <NA>   <NA>  foreign word        外国語        d'<U+0153>uvre        
## 6 IN    preposit~ <NA>   <NA>  preposition/subord~ 前置詞または従属接続詞~ in,of,like,aft~

 ちなみに対応表は完成していません、、、(とりあえず名詞・動詞・形容詞分かればそれで。。)

# 品詞大分類の対応表
wclass_data <- pos_data %>% 
  select(wclass, POS1) %>% # 品詞(大分類)の列を取り出す
  filter(!is.na(wclass)) %>% # NAの行を除外
  distinct(wclass, .keep_all = TRUE) # 重複を除外

# 品詞細分類の対応表
tag_data <- pos_data %>% 
  select(tag, POS2) %>% # 品詞(細分類)の列を取り出す
  filter(!is.na(tag)) # NAの行を除外

 品詞wclassを品詞大分類POS1、品詞コードtagを品詞細分類POS2として用います。それぞれ取り出してデータフレームにします。

・docDF()仕様に変換

 では、解析結果のデータフレームをdocDF()仕様に変換します。

# RMeCab風に変換
mc_data <- tt_data %>% 
  left_join(wclass_data, by = "wclass") %>% # 品詞(大分類)情報を結合
  left_join(tag_data, by = "tag") %>% # 品詞(細分類)情報を結合
  select(TERM, POS1, POS2, all_of(file_name)) # 必要な列を取り出す

 left_join()で品詞情報列を結合することで、日本語品詞情報を与えます。(foctorsのレベルが違うという警告メッセージが出ます。)

tail(mc_data)
## # A tibble: 6 x 4
##   TERM      POS1   POS2   wonderful_world.txt
##   <chr>     <chr>  <chr>                <int>
## 1 what      名詞   Wh                       1
## 2 with      <NA>   <NA>                     2
## 3 wonderful 形容詞 <NA>                     4
## 4 world     名詞   <NA>                     4
## 5 you       名詞   代名詞                  18
## 6 your      名詞   代名詞                   5

 これで完成です(NAなのは、対応表を埋め切れていないためです)。

 一応直接docDF()で処理した場合の出力も確認しておきます。

# (確認用)MeCabによる形態素解析
res_mc <- docDF(paste(folder_name, file_name, sep = "/"), type = 1) %>% 
  as_tibble()
tail(res_mc)
## # A tibble: 6 x 4
##   TERM      POS1  POS2  wonderful_world.txt
##   <chr>     <chr> <chr>               <int>
## 1 with      名詞  一般                    2
## 2 wonderful 名詞  一般                    4
## 3 world     名詞  一般                    4
## 4 you       名詞  一般                   12
## 5 your      名詞  一般                    5
## 6 …         記号  一般                    1

 品詞が全て名詞になってしまいます。

フォルダ単位の出力をdocDF()仕様に変換

 続いて、フォルダを丸ごと処理する場合です。

# フォルダ名を指定
folder_name <- "text_data/lyrics_avr"

# ファイル名を取得
file_name_list <- list.files(path = folder_name, pattern = "txt")

 ディレクトリを指定して、その中のファイル名を取得します。

 形態素解析を行います。

# TreeTaggerによる英文形態素解析
tt_data <- tibble(
  TERM = character(), 
  wclass = factor(), 
  tag = factor()
)
for(i in seq_along(file_name_list)) {
  
  # ファイル名を抽出
  file_name <- file_name_list[i]
  
  # 形態素解析
  res_tt <- taggedText(treetag(paste(folder_name, file_name, sep = "/"))) %>% 
    as_tibble()
  
  # 必要なデータを抽出
  tmp_tt_data <- res_tt %>% 
    select(lemma, wclass, tag) %>% # 必要な列を取り出す
    count(lemma, wclass, tag) %>% # 単語の出現頻度を集計
    rename(TERM = lemma, !!file_name := n) %>% # RMeCab仕様に列名を変更
    arrange(TERM) # 昇順に並べ替え
  
  # 結果を結合
  tt_data <- full_join(tt_data, tmp_tt_data, by = c("TERM", "wclass", "tag"))
}

# NAを0に置換
tt_data[is.na.data.frame(tt_data)] <- 0

 1つずつ処理して、結果を結合していきます。

 テキストに含まれない単語の頻度がNAとなるので、0に置換します。

head(tt_data[, 1:8], 10)
## # A tibble: 10 x 8
##    TERM  wclass tag   avr_001.txt avr_002.txt avr_003.txt avr_004.txt
##    <chr> <chr>  <chr>       <dbl>       <dbl>       <dbl>       <dbl>
##  1 '     posse~ POS             8           0           0           0
##  2 '     punct~ ''              4           2           0           0
##  3 -     punct~ :               1           1           0           1
##  4 (     punct~ (              11           1           0           0
##  5 )     punct~ )              11           1           0           0
##  6 @car~ number CD              1          11           0           0
##  7 and   conju~ CC              6           7           0           5
##  8 arou~ adverb RB              1           0           0           3
##  9 arou~ prepo~ IN              1           0           0           1
## 10 Avril name   NP              1           1           0           1
## # ... with 1 more variable: avr_005.txt <dbl>

 こんな感じになるはずです。

 RMeCab::docDF仕様に変換します。

# RMeCab風に変換
mc_data <- tt_data %>% 
  left_join(wclass_data, by = "wclass") %>% # 品詞(大分類)情報を結合
  left_join(tag_data, by = "tag") %>% # 品詞(細分類)情報を結合
  select(TERM, POS1, POS2, all_of(file_name_list)) # 必要な列を取り出す

 頻度列がテキストファイル数分になるので、file_name_listを指定する点が異なります。

head(mc_data[, 1:8], 10)
## # A tibble: 10 x 8
##    TERM  POS1  POS2  avr_001.txt avr_002.txt avr_003.txt avr_004.txt avr_005.txt
##    <chr> <chr> <chr>       <dbl>       <dbl>       <dbl>       <dbl>       <dbl>
##  1 '     <NA>  <NA>            8           0           0           0           0
##  2 '     記号  <NA>            4           2           0           0           0
##  3 -     記号  一般結合~           1           1           0           1           0
##  4 (     記号  <NA>           11           1           0           0           0
##  5 )     記号  <NA>           11           1           0           0           0
##  6 @car~ 名詞  数              1          11           0           0           0
##  7 and   接続詞~ <NA>            6           7           0           5           0
##  8 arou~ 副詞  <NA>            1           0           0           3           0
##  9 arou~ <NA>  <NA>            1           0           0           1           0
## 10 Avril <NA>  <NA>            1           1           0           1           0

 これで完成です。

# (確認用)MeCabによる形態素解析
res_mc <- docDF(folder_name, type = 1) %>% 
  as_tibble()
head(res_mc[, 1:8], 10)
## # A tibble: 10 x 8
##    TERM  POS1  POS2  avr_001.txt avr_002.txt avr_003.txt avr_004.txt avr_005.txt
##    <chr> <chr> <chr>       <int>       <int>       <int>       <int>       <int>
##  1 "!"   名詞  サ変接続~           0           4           0           0           0
##  2 "!)"  名詞  サ変接続~           0           0           0           0           0
##  3 "!,"  名詞  サ変接続~           0           0           0           0           0
##  4 "\""  名詞  サ変接続~           0           0           0           0           0
##  5 "\"," 名詞  サ変接続~           0           0           0           0           0
##  6 "&"   名詞  サ変接続~           0           0           0           0           0
##  7 "'"   名詞  サ変接続~          45           3           0          20           0
##  8 "',"  名詞  サ変接続~           0           0           0           0           0
##  9 "'..~ 名詞  サ変接続~           0           0           0           0           0
## 10 "("   名詞  サ変接続~          11           1           0           0           0

 直接処理するとこのように出力されます。

 以上!

参考文献

 品詞の情報については一部こちらのページのものを使わせていただきました。

computer-technology.hateblo.jp


おわりに

 私は歌詞を分析したいんです!J-POPの歌詞って英文が混じってるんですよね。それでMeCabだけじゃダメじゃんとなって、こういうことが必要になりました。

 対応表はいつか完成させます。いつかね。

 そろそろホントにfor()使いを卒業したい。

 2020年07月17日!元こぶしファクトリー現Juice=Juice井上玲音さん19歳のお誕生日!れいれいおめでとおおお!!