備忘ログ

チラシの裏的備忘録&メモ

Rでe-statからxls(xlsx)ファイルをダウンロードするときにうまくいかなかったときに対処したメモ

要旨

  1. Rでe-statのXLS形式のファイルをダウンロードするときdownload.file()ではうまくいかなかったが、{httr}パッケージのGET()write_disk()を使ったらうまくいった。
  2. e-statのapiの仕様の関係でXLS形式のファイルが.xlsなのか.xlsxなのかはわからないが、{tidyxl}maybe_xlsx()を使うと判別できる。

政府統計の総合窓口のe-statが提供する統計データを取得するときに、Rでe-statのapiをいい塩梅に回してくれる{estatapi}ではXLS形式のデータはestat_getStatsData()では取得できない。

これは、estat_getDataCatalog()を実行して、データダウンロード用のURLを参照しファイルをダウンロードすると解決できる。

これは次のブログが詳しい(というかこれを見て知った)。

uribo.hatenablog.com

で、XLS形式のファイルをダウンロードする方法として上記のブログではdownload.file()を紹介しているが、これは現在自分の環境ではうまくいかなかった。関数やAPIの仕様の変更によるものかもしれないし、環境依存でうまくいかない要素が自分にあるのかもしれない。

上記のブログの例に従ってデータをダウンロードすると、ダウンロードしたファイルをExcelで開こうとすると次のように「ファイルの一部の内容に問題が見つかりました。可能な限り内容を回復しますか?」などのメッセージがでて「はい」を選択しても開けないことや、中身のデータが壊れてしまっていて読めないという事案に遭遇した(methodなどの引数をいじってもだめだった)。

そこで代わりに{httr}パッケージのGET()write_disk()を使うとうまくいった。

次の例では{estatapi}の代わりに自作の{estatapi.appId}というパッケージをつかっているが、これはappIdを入力するのめんどくさいという自分の要望を満たすための{estatapi}のラップ関数群なので、実態はappIdを入力(または引数で指定)しなくてもよくなるというだけのもので実態は一緒である。

詳細はこのブログの通り。

indenkun.hatenablog.com

library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.4.1     ✔ purrr   1.0.1
## ✔ tibble  3.1.8     ✔ dplyr   1.1.0
## ✔ tidyr   1.3.0     ✔ stringr 1.5.0
## ✔ readr   2.1.4     ✔ forcats 1.0.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
library(estatapi.appId)
# 例として小学校の教職員データを取り出す
# XLS形式だけカタログで取り出したいのでdataTypeで指定する。
df.list <- estat_getDataCatalog(searchWord = "学校基本調査 AND 職名別教員数(本務者)AND 小学校", dataType = "XLS")
df.list <- df.list |>
  filter(TABLE_NAME ==  "職名別教員数(本務者)")

df.listに格納されるデータの1つ目をURLを指定して{httr}GET()write_disk()をつかってダウンロードすると次のようになる。

library(httr)
GET(df.list$URL[1],
    write_disk(path = paste0("dl_file1.", tolower(df.list$FORMAT[1])), overwrite = TRUE))
## Response [https://www.e-stat.go.jp/stat-search/file-download?&statInfId=000001227925&fileKind=0]
##   Date: 2023-02-14 05:26
##   Status: 200
##   Content-Type: application/octet-stream
##   Size: 114 kB

でダウンロードすることができる。

あとはほしいファイルを指定してダウンロードする処理をかけばよい。

ところで、e-statのapiの仕様上、ExcelのファイルがXLS形式となっていると返されるので、これが.xlsか.xlsxかはわからない。

たとえば上記の小学校データだと、最近のデータは.xlsx形式となっている。

とりあえず最新の2022年データをdl_file2.xlsとしてダウンロードしてみる。

GET(df.list$URL[df.list$SURVEY_DATE == 2022],
    write_disk(path = paste0("dl_file2.", tolower(df.list$FORMAT[df.list$SURVEY_DATE == 2022])), overwrite = TRUE))
## Response [https://www.e-stat.go.jp/stat-search/file-download?&statInfId=000032264739&fileKind=0]
##   Date: 2023-02-14 05:26
##   Status: 200
##   Content-Type: application/octet-stream
##   Size: 40.1 kB

ダウンロードしたファイルが実は.xlsxだったときに、write_disk()で.xlsと名前をつけてもExcelで開けないことはないが、ファイル形式違いませんか?と一度聞かれる。

また、本当は.xlsxのファイルを.xlsと拡張子つけていて、{readxl}パッケージでファイルを読み込むときに、read_xls()read_excel()でうまく開けないことがある。read_xlsx()を使うと正しく開けるが、そのためには本当の拡張子を知っている必要がある。

そもそも本当の拡張子になっていれば、read_excel()で開けるので、拡張子を正しく判定したい。しかし、そのために毎回Excelで開くのはめんどくさいので、{tidyxl}を使うとだいたい判別できる(だいたいというけんについては関数のドキュメントにある)。

library(tidyxl)
maybe_xlsx("dl_file1.xls")
## [1] FALSE
maybe_xlsx("dl_file2.xls")
## [1] TRUE

xlsとxlsxの判別ができたので、xlsxは{readxl}で読み込むときにread_xlsx()で読み込むか拡張子を書き換えてread_excel()で読めるようにする方策が立つようになる。

例えば次のようにするとファイル名がRから簡単に書き換えられる。

file.rename("dl_file2.xls", "dl_file2.xlsx")

なのでたとえばファイルのリストをもっていれば次のように判定してxlsxなら書き換える風にすると簡便にいける。

library(purrr)
file_name <- c("dl_file1.xls", "dl_file2.xls")
walk(file_name, function(x) if(maybe_xlsx(x)) file.rename(x, paste0(x, "x")))

ちなみに、ダウンロードしたExcel形式は最近のものは取り扱いやすいが、古めのものはセルの結合などがいろいろやられていて取り扱いしにくい場合が多いが、そこは頑張るしかない。

余談としては、e-stat上にはExcel形式しかないデータがちょいちょいあるので過去の資産も含めて少しずつでもDB化して欲しい(してる感じもある?ただ自分が見てみるデータは結構Excel形式しかないことが多い気がする)。