cucumber flesh

Rを中心としたデータ分析・統計解析らへんの話題をしていくだけ

📦{tm}パッケージで日本語のPDFからテキストを抽出する

男なら誰しも一度は「俺に落とせない女はいない」、的なことを言ってみたいと思うわけですが、どうやらそんなセリフを言う機会がありそうもないので、「俺に落とせないデータはない」くらいにスケールダウンかつハッカー感を出していければと思います。

というわけでタイトルにある通り、日本語のPDFからテキストを抽出する方法です。テキストマイニングに特化した{tm}パッケージを使います。

まず、通常の{tm}の挙動を見てから、日本語PDFへの応用例を示します。

library(tm)

🔧 tm::readPDF() の基本動作

PDFからR上にテキストを落とすreadPDF()の基本的な使い方です。

対象にするのは、欲しいなー誰か買ってくれないかなーと狙っている "Zero Inflated Models and Generalized Linear Mixed Models with R"の目次PDFにします。動作を確認したい人は適宜ダウンロードしてきてください(デスクトップ上にContents.pdfというファイル名でおきました)。

readPDF()を動作させるためには次のシステムが必要です。パスが表示されるかを確認しましょう。

Sys.which(c("pdfinfo", "pdftotext"))
##                    pdfinfo                  pdftotext 
##   "/usr/local/bin/pdfinfo" "/usr/local/bin/pdftotext"
# tm_res() という関数を用意する
tm_res <- readPDF(control = list(text = "-layout"))
# tm_res()は次の引数名をもつ
tm_res %>% args() %>% as.list() %>% names()
## [1] "elem"     "language" "id"       ""

engineに指定する引数は初期値のxpdfで良いと思われるので、特に指定する必要はありません。その他のシステムを利用したい時には変更してください。xpdfの他に、Rpoppler、ghostscript、Rcampdfおよびカスタマイズしたシステムが利用できます。

# elem引数にリスト形式でファイルまでのパス、language引数を指定し、関数を実行する
tm_res %<>% .(elem = list(uri = "/Users/user/Desktop/Contents.pdf"), 
              language = "en")
tm_res %>% class()
## [1] "PlainTextDocument" "TextDocument"

readPDF()の返り値はこのようなクラスオブジェクトになっています。また、

tm_res %>% str(max.level = 2)
## List of 2
##  $ content: chr [1:247] "VIII Contents" "" "Contents" "" ...
##  $ meta   :List of 7
##   ..$ author       : chr "Highstat"
##   ..$ datetimestamp: POSIXlt[1:1], format: "2012-01-29 21:14:55"
##   ..$ description  : chr ""
##   ..$ heading      : chr "FrontMatterF"
##   ..$ id           : chr "Contents.pdf"
##   ..$ language     : chr "en"
##   ..$ origin       : chr "Word"
##   ..- attr(*, "class")= chr "TextDocumentMeta"
##  - attr(*, "class")= chr [1:2] "PlainTextDocument" "TextDocument"

のように、テキストそのものはtm_res$contentに格納されています。tm_res$contentは文字列クラスオブジェクトです。すべてを表示させると長いので、先頭のいくつかのみを表示させます。

tm_res$content[1:10]
##  [1] "VIII Contents"                                                                                                                                                                                  
##  [2] ""                                                                                                                                                                                               
##  [3] "Contents"                                                                                                                                                                                       
##  [4] ""                                                                                                                                                                                               
##  [5] "PREFACE\t\r  ........................................................................................................................................................\tV\r   \t\r  "            
##  [6] "CONTENTS\t\r  ..................................................................................................................................................\tV\r   III\t\r  "              
##  [7] "1\t\r  INTRODUCTION\t\r  TO\t\r  BAYESIAN\t\r  STATISTICS,\t\r  MCMC\t\r  TECHNIQUES,\t\r  AND\t\r  WINBUGS\t\r  ........................................\t\r 1  \t\r  "                        
##  [8] ""                                                                                                                                                                                               
##  [9] "       1.1\t\r  PROBABILITIES\t\r  AND\t\r  BAYES’\t\r  THEOREM\t\r  .............................................................................................................\t\r  1\t\r  "
## [10] "       1.2\t\r  LIKELIHOOD\t\r  FUNCTIONS\t\r .  ...............................................................................................................................\t\r  3\t\r  "

というようにPDFから文字をR上に抽出できました。あとの処理は通常のRでのテキストマイニングの手法を適用すればおkです。

🇯🇵 日本語PDFでも文字抽出

さて、同様の手法を日本語が含まれるPDFに対して実行すると、アルファベットや数字は抽出することができますが、肝心の日本語が抽出できません。そこで、

[http://akkunchoi.github.io/xpdf-japanese.html:embed:cite]

このページにあるように、必要なツールをインストールしたのち、xpdfの内容に修正を加えておきます。これで準備は整いました。日本語PDFの例として、

総務省|政策統括官(統計基準担当)|統計に用いる標準地域コード

にある 「41 佐賀県~47 沖縄県(PDF:145KB)」を対象にします。ダウンロードしたファイルは000323624.pdfという名称です。

tm_res <- readPDF(control = list(text = "-layout"))
tm_res %<>% .(elem = list(uri = "/Users/user/Desktop/000323624.pdf"), language = "ja")

結果です。例によって一部を取り出してみます。

tm_res$content[1:10]
##  [1] "41 佐 賀 県            346 み や き 町 みやきちょう"
##  [2] ""                                                   
##  [3] "200 市  部            360 削   除(旧小城郡)"      
##  [4] "                    361 削   除"                    
##  [5] "201 佐 賀 市 さがし       362 削   除"              
##  [6] "                    363 削   除"                    
##  [7] "202 唐 津 市 からつし      364 削   除"             
##  [8] ""                                                   
##  [9] "203 鳥 栖 市 とすし"                                
## [10] ""

というわけで日本語のPDFでもテキストを落とすことができて、小さな小さな自尊心が保たれました。

🍵 おまけ

せっかくなので市区郡町村のデータフレームを作成してみました。

library(tidyr)
library(dplyr)
res_city <- tm_res$content %>% 
  grep("\\d{3}", ., value = TRUE) %>% 
  grep("削|除", ., invert = TRUE, value = TRUE) %>% 
  grep("[市区郡町村]", ., value = TRUE) %>% 
  gsub(".+[0-9] ", "", .)

res_city %<>% data_frame(city = .) %>% 
  tidyr::extract(col  = city,
                 into = c("name", "rubi"),
                 regex = "(.+[市区郡町村]+)+([[:print:]]+)",
                 remove = TRUE) %>%
  dplyr::mutate(name = gsub("[[:space:]]", "", name)) %>% 
  dplyr::filter(!is.na(name))

f:id:u_ribo:20151129134400p:plain

参考