TIF:テキスト分析用Rパッケージのデザインの紹介
R Advent Calendar 2021 1日目でした
Text Interchange Formats(TIF)とは?
Text Interchange Formats(TIF)は、2017年にrOpenSci Text Workshopで整備された「こんな感じでテキスト分析用のRパッケージをデザインしましょう!」という仕様みたいなものです。
まだドラフト段階らしいのですが、たとえばquantedaなどはこの仕様に沿ってデザインされているようです。
実際のところ、この仕様に沿ったからといってそれ自体ではどうということでもないのですが、一応、他のパッケージと組み合わせて使いやすくなるだろうというモチベーションはあって、筆者が個人で開発しているパッケージの一部でもこの仕様を意識しています。
以下では、TIFってこんな感じの見た目になるやつですということを自作パッケージにおける実装の例を交えながら、ごく簡単に紹介します。
Corpus:コーパス
TIFではコーパス(corpus)、文書単語行列(dtm)、トークン(token)という要素が定義されています。
このうち文書の集合であるコーパスは、データフレームか名前付きベクトルの形式で保持します。いずれも文字エンコーディングはUTF-8であることが前提されています。
Corpus(data frame)
データフレーム形式のコーパスは、少なくともdoc_id
とtext
という列を含むデータフレームです。doc_id
列は文書によって一意なID列(character型である必要がある)で、text
列は文書本体です。「少なくとも」なので、このほかの列に文書のメタ情報などが含まれていてもよいことになっています。
ちなみに、このかたちのデータフレームはreadtextパッケージを使うと簡単に得ることができます。
corp1 <- data.frame(
doc_id = c("text1", "text2", "text3"),
text = c("ひとつめの文書", "ふたつめの文書", "みっつめの文書")
)
Corpus(character vector)
ベクトル形式のコーパスは、文書のIDを各要素の名前にした、名前付きの文字列ベクトル(named character vector)です。
corp2 <- c(
"text1" = "ひとつめの文書",
"text2" = "ふたつめの文書",
"text3" = "みっつめの文書"
)
なお、筆者が開発している形態素解析ができるパッケージでは、基本的にこの形式のコーパスから処理することを想定しています。文書レベルのメタデータも保持したくて、データフレーム形式のコーパスと結合したい場合などには、次のようなかたちで分かち書きした文書をtext
列に持つコーパスを経由することができます。
library(magrittr)
corp2 <- c(
"text1" = "ひとつめの文書",
"text2" = "ふたつめの文書",
"text3" = "みっつめの文書"
)
rjavacmecab::igo(corp2) %>%
rjavacmecab::prettify() %>%
rjavacmecab::pack()
#> doc_id text
#> 1 text1 ひと つめ の 文書
#> 2 text2 ふたつ め の 文書
#> 3 text3 みっ つめ の 文書
dtm:文書単語行列
いわゆる「文書単語行列(document-term matrix, DTM)」は、各行が文書で、各列が単語である疎行列オブジェクト(dgCMatrix of 'Matrix' package)です(quantedaの実装があるのでここは自分で再実装することはなさそう)。
tokens:トークン
トークンは、コーパスを文書ごとにいい感じの単位にまとめあげながら格納したものです。それぞれのトークンは単語とかngramとかだったりを想定しています。
tokens(data frame)
データフレーム形式のトークンは、各行が一つのトークンであるようなデータフレームです。少なくともdoc_id
列(character型である必要がある)とtoken
列が含まれる必要があります。以下のような感じのやつで、実際にはトークンごとのメタデータ(品詞情報など)が付くことになります。
toks1 <- data.frame(
doc_id = c("text1", "text1", "text1", "text1",
"text2", "text2", "text2", "text2",
"text3", "text3", "text3", "text3"),
token = c("ひとつ", "め", "の", "文書",
"ふたつ", "め", "の", "文書",
"みっつ", "め", "の", "文書")
)
したがって、だいたい次のようなかたちのデータフレームになります。
library(magrittr)
corp2 <- c(
"text1" = "ひとつめの文書",
"text2" = "ふたつめの文書",
"text3" = "みっつめの文書"
)
rjavacmecab::igo(corp2) %>%
rjavacmecab::prettify()
#> doc_id token POS1 POS2 POS3 POS4 X5StageUse1 X5StageUse2 Original
#> 1 text1 ひと 接頭詞 名詞接続 <NA> <NA> <NA> <NA> ひと
#> 2 text1 つめ 名詞 一般 <NA> <NA> <NA> <NA> つめ
#> 3 text1 の 助詞 連体化 <NA> <NA> <NA> <NA> の
#> 4 text1 文書 名詞 一般 <NA> <NA> <NA> <NA> 文書
#> 5 text2 ふたつ 名詞 一般 <NA> <NA> <NA> <NA> ふたつ
#> 6 text2 め 名詞 接尾 一般 <NA> <NA> <NA> め
#> 7 text2 の 助詞 連体化 <NA> <NA> <NA> <NA> の
#> 8 text2 文書 名詞 一般 <NA> <NA> <NA> <NA> 文書
#> 9 text3 みっ 動詞 自立 <NA> <NA> 五段・タ行 連用タ接続 みつ
#> 10 text3 つめ 名詞 一般 <NA> <NA> <NA> <NA> つめ
#> 11 text3 の 助詞 連体化 <NA> <NA> <NA> <NA> の
#> 12 text3 文書 名詞 一般 <NA> <NA> <NA> <NA> 文書
#> Yomi1 Yomi2
#> 1 ヒト ヒト
#> 2 ツメ ツメ
#> 3 ノ ノ
#> 4 ブンショ ブンショ
#> 5 フタツ フタツ
#> 6 メ メ
#> 7 ノ ノ
#> 8 ブンショ ブンショ
#> 9 ミッ ミッ
#> 10 ツメ ツメ
#> 11 ノ ノ
#> 12 ブンショ ブンショ
tokens(list)
リスト形式のトークンは、文書のIDを各要素の名前にした、文字列ベクトルのリスト(possibly named list of character vectors)です。各要素がそのままトークンになるため、こちらにはトークンレベルのメタデータは一切付きません。
toks2 <- list(
"text1" = c("ひとつ", "め", "の", "文書"),
"text2" = c("ふたつ", "め", "の", "文書"),
"text3" = c("みっつ", "め", "の", "文書")
)
実際には、次のようなかたちになります。
corp2 <- c(
"text1" = "ひとつめの文書",
"text2" = "ふたつめの文書",
"text3" = "みっつめの文書"
)
rjavacmecab::igo(corp2, mode = "wakati")
#> $text1
#> [1] "ひと" "つめ" "の" "文書"
#>
#> $text2
#> [1] "ふたつ" "め" "の" "文書"
#>
#> $text3
#> [1] "みっ" "つめ" "の" "文書"
Discussion