cucumber flesh

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

タイル形式にデータを並べて表示するtabularmapsパッケージがCRANに登録されました

新しいパッケージをCRANに登録しました。tabularmapsパッケージです。このRパッケージは以前ブログ記事にも書いた、 カラム地図を作成するためのものです。カラム地図は、行政区などの配置を表状に敷き詰めて表示することで、それぞれの位置関係をわかりやすく伝えられる利点のある可視化方法の一つです。

uribo.hatenablog.com

主要な機能は前回の記事と変わっていませんが、細かな挙動が変わったので改めて使い方を紹介します。

まずはパッケージをCRANからインストール。開発版を利用する方はGitHub経由でインストールしてください。

# CRAN版
install.packages("tabularmaps")

# 開発版
if (!requireNamespace("remotes"))
  install.packages("remotes")
remotes::install_github("uribo/tabularmaps")

tabularmapsの可視化はggplot2をベースにしているので一緒に読み込んでおくことを推奨します。

library(ggplot2)
library(tabularmaps)

tabularmapsでは任意のデータを利用可能です。また、サンプルとしていくつかのデータが備わっています。ここでは日本の都道府県の位置関係を簡略化したデータを例にしてパッケージの使い方を見ていきましょう。

カラム地図を作成する関数はtabularmaps()です。この関数の引数に対象のデータ、項目を配置させる位置を記録したx、y座標の値が含まれる変数名を指定します。加えて、項目の識別子となる変数をgroup、表示するラベルの変数名をlabelの引数にそれぞれ与えます。ここで、塗り分けの変数が存在する場合にはfill引数にその値を指定してください。

p <- 
  tabularmap(data = jpn77,
           x = x,
           y = y,
           group = jis_code,
           label = prefecture_kanji,
           fill = region_kanji,
           # 図中のlabel文字列(prefecture_kanji)の日本語表示のためのフォント指定
           family = "IPAexGothic")
p

f:id:u_ribo:20200812074924p:plain

上記の例がシンプルなカラム地図の作成方法になります。ここからアレンジしてみましょう。先ほどのコードの実行結果を保存したpオブジェクトに対して2つの関数を追加します。

p +
  scale_fill_jpregion(lang = "jp") +
  theme_tabularmap(base_family = "IPAexGothic")

f:id:u_ribo:20200812074936p:plain

scale_fill_jpregion()は日本の地方名を凡例にする際の専用の関数です。これは元々のカラム地図で使われている色を簡単に各地方に割り当てることができる関数です。ラベルが日本語・英語の場合に対応できるよう、引数langを設定します。もう一つの関数はtheme_tabularmap()です。これはggplot2::theme_minimal()の簡単なラッパです。カラム地図では特に軸ラベルなどの表記が不要なため、そうした要素を非表示にするggplot2のテーマを設定します。

以上の例では組み込みのデータセットを使いましたが、tabularmapsでは任意のデータを使ってカラム地図を作成できます。その際、各要素を配置する座標(x,y)、ラベルなどを用意してください。

タイルの角を丸くするオプション

今回のCRAN登録にあたって、各要素、つまりタイルの輪郭に対する調整を行うオプションを追加しました。カラム地図はタイルを敷き詰めたように表示するのがオリジナルですが、これを丸くして表示するオプションです。

このオプションは引数.radius_sizeで調整します。デフォルトでは2が与えられますが、この数値を大きくるするとタイルの角が丸くなります。

tabularmap(tky23,
           x,
           y,
           group = ward,
           fill = ward,
           label = ward_kanji,
           family = "IPAexGothic",
           .radius_size = 30) +
  theme_tabularmap(base_family = "IPAexGothic") +
  guides(fill = FALSE)

f:id:u_ribo:20200812074957p:plain

画面右側の図が.radius_sizeを変更したものです。同じ形で規則的に並んでいるのでカラム地図と同じような効果があると思います。

geom_tabularmps?

本当は他のggplot2関連パッケージのようにgeom_*()として関数を実装したかったのですが、今回は能力不足で至りませんでした。改善したいです。

というわけで、まだ出来たばかりでアラの多いtabularmapsパッケージですが、ぜひ使ってみてください(おかしな点があればissue報告いただけますと幸いです)。

github.com

Enjoy!

Tokyo.R#87でdata.tableパッケージの発表をしました

先日開催された第87回Tokyo.Rにおいてdata.tableパッケージに関する発表を行いました。 ここでは発表資料へのリンクと補足を書きます。

今回のスライド作成に関して、GitHubスポンサーの皆さんからの援助を受けています。 どうもありがとうございました。この場を借りて感謝いたします。

発表内容

当日の資料をspeakerdeckにアップロードしています。

speakerdeck.com

今こそ、data.tableを学ぼう! / datatable1130 - Speaker Deck

共有した画面上でカラーピッカーがデカデカと表示されたまま進行してしまったようで、どうもすみませんでした。 ご指摘ありがとうございました。

dplyrとの使い分け

data.tableパッケージはしばしば、データ操作という観点でdplyrパッケージとともに引き合いに出されます。 Rでのデータ操作といえばdplyr!そういう流れを感じますし、自分自身もdplyrファンで普段のコードもdplyr含めたtidyverseのものを使っています。 一方で時々、人様のコードを読む機会があるとdata.tableパッケージを使うものに遭遇します。 その時、data.tableで処理されたコードが読めないと困ります。

data.tableとdplyrを使ったデータ操作のコードの大きな違いは、

  • data.table: データを宣言し、[の内部でデータへの処理を記述する
  • dplyr: verbと呼ばれるデータに対する振る舞いを関数化、必要に応じてパイプ演算子%>%)によって処理を繋げていく

です。dplyrに馴染んでいる私は、パイプ演算子の出てこないコードに立ちすくんでしまうことがありました。 (逆にdata.tableをメインに使うのであったらパイプ演算子が出てくるコードを見ても謎に感じるのではないでしょうか)

data.tableでの処理は(覚えてしまうと)シンプルです。dplyrのように複数の関数の挙動を覚える必要がありません。 対象のデータ(data.tableオブジェクト)に対して [演算子を使い、その中で次の画像に示す規則で処理を記述することになります。

f:id:u_ribo:20200806085002j:plain

data.tableの文法を効率的に学習するにはdplyrでの処理と比較したら良いのではと思い、今回のスライドではdplyrのコードも掲載しています。

現実的な使い分けについてはTwitterで頂いたコメントへの返信の通り

普段使いのコードは馴染みのあるものを、ただ必要に迫られた際のためにどちらも覚えておくと良い、 と身も蓋もない話になってしまいますがそう思います。

スライド作成

フォント

発表後のチャット欄で「フォントは何を使っているか」という質問がありました。今回のスライドで用いたフォントは以下の通りです。

  • Canela Text
  • Font Awesome 5 Brands
  • FOT-ラグランパンチ
  • FOT-ロックンロール
  • Hack
  • Rockwell

このうち、「ラグランパンチ」、「ロックンロール」はフォントワークスmojimoサービスが提供するフォントパックに含まれるものです。「ラグランパンチ」はアニメ「キルラキル」やゲームソフトの「ゼルダの伝説 Breath of the world」で使われているものです。インパクトがあって見出しに適していますね。お気に入りです。

f:id:u_ribo:20200806090300j:plain

36書体が、年間定額

利用するコンピュータは一台のみの制約がありますが、切り替えもシンプルなので年間3,600円はお得です。 フォントを契約する余裕が生まれたのはGitHubスポンサーで支援してくださる方がいたためです。 発表の機会が増えるなら買ってしまえ、と契約に至りました。

カラーパレット

pals::pal.bands(c("#040A0F", "#EB6257", "#E98353", "#F1B952", "#F3CF50", "#F4EDCD"))

f:id:u_ribo:20200806083349p:plain

  • #040A0F
  • #EB6257
  • #E98353
  • #F1B952
  • #F3CF50
  • #F4EDCD

最初は違う色を使っていましたが、どうも馴染まなくて一部を変更しました。そのせいもあってか、普段は4~5色に抑えようとしているので、少し多くなってしまいました。 ドイツっぽいなーと思いますw

Enjoy!

市区町村役所間の距離行列を求める~pdftoolsでのデータ抽出とsfによる算出編~

はじめに

Qiitaのなかで@3tkyさんが、都道府県庁間の距離行列をRで求める記事を書かれていました。

qiita.com

そして、挑戦状のような一文が残されています。

市区町村の役所の緯度経度は 国土地理院 がまとめているので、PDFを整形し、60進法表記を @uri さんのkuniezuパッケージ や pazerパッケージを活用して10進法に変換後、上のコードから市区町村役所間の距離行列が作成できそう。

これはやらねばなるまい(謎の使命感)。 本記事では、[@3tky](https://qiita.com/3tky) さんの書かれていた都道府県庁間の距離行列を算出する方法の別解と同様に市区町村役所の距離行列を求める方法を書きます。 大元の市区町村の役所の緯度経度データは国土地理院が公開するPDFデータです。そのためPDFからデータを抽出、加工する方法についても言及します。

記事の中で以下のパッケージを利用します。予め読み込んでおきましょう。

library(sf)
library(ggplot2)
library(rvest)
# library(units)
# library(tidyverse)

都道府県庁間の距離行列

記事を見たあと、CRANにリリース準備だった kuniezu パッケージに都道府県の県庁位置のデータを収納しました。 このデータの取得・整形するコードは

https://github.com/uribo/kuniezu/blob/master/data-raw/office_locaiton.R

に置いています。

data("jp47prefectural_offices", package = "kuniezu") # 47都道府県の県庁位置データ
jp47prefectural_offices
## Simple feature collection with 47 features and 1 field
## geometry type:  POINT
## dimension:      XY
## bbox:           xmin: 127.681114197 ymin: 26.2124996185 xmax: 141.346939087 ymax: 43.0641670227
## CRS:            EPSG:4326
## # A tibble: 47 x 2
##    office                        geometry
##    <chr>                      <POINT [°]>
##  1 北海道庁 (141.346939087 43.0641670227)
##  2 青森県庁 (140.740005493 40.8244438171)
##  3 岩手県庁 (141.152496338 39.7036094666)
##  4 宮城県庁 (140.871948242 38.2688903809)
##  5 秋田県庁 (140.102493286 39.7186126709)
##  6 山形県庁 (140.363327026 38.2405548096)
##  7 福島県庁         (140.467773438 37.75)
##  8 茨城県庁 (140.446670532 36.3413887024)
##  9 栃木県庁 (139.883605957 36.5658340454)
## 10 群馬県庁 (139.060836792 36.3911094666)
## # … with 37 more rows

まずは対角要素が0となる距離行列を作成します。sfオブジェクトでの地物間の距離は st_distance() を使って求められます。

dist_pref <-
  jp47prefectural_offices %>%
  st_distance()
colnames(dist_pref) <- jp47prefectural_offices$office
rownames(dist_pref) <- jp47prefectural_offices$office
dist_pref[seq_len(6), seq_len(6)]
## Units: [m]
##               北海道庁      青森県庁       岩手県庁      宮城県庁
## 北海道庁      0.000000 253808.763222 373582.0205556 534013.529177
## 青森県庁 253808.763222      0.000000 129308.2699883 283959.259182
## 岩手県庁 373582.020556 129308.269988      0.0000000 161119.538069
## 宮城県庁 534013.529177 283959.259182 161119.5380689      0.000000
## 秋田県庁 385850.690256 134229.605213  90055.4114243 174198.478652
## 山形県庁 542058.359064 288699.213957 176229.8003421  44629.402174
##                秋田県庁      山形県庁
## 北海道庁 385850.6902557 542058.359064
## 青森県庁 134229.6052134 288699.213957
## 岩手県庁  90055.4114243 176229.800342
## 宮城県庁 174198.4786523  44629.402174
## 秋田県庁      0.0000000 165635.769370
## 山形県庁 165635.7693696      0.000000

また、距離の単位はmですが units パッケージの関数を使って任意の単位に変更可能です。

dist_pref <- 
  dist_pref %>% 
  units::set_units(km)
dist_pref[seq_len(6), seq_len(6)]
## Units: [km]
##               [,1]          [,2]           [,3]          [,4]           [,5]
## [1,]   0.000000000 253.808763222 373.5820205556 534.013529177 385.8506902557
## [2,] 253.808763222   0.000000000 129.3082699883 283.959259182 134.2296052134
## [3,] 373.582020556 129.308269988   0.0000000000 161.119538069  90.0554114243
## [4,] 534.013529177 283.959259182 161.1195380689   0.000000000 174.1984786523
## [5,] 385.850690256 134.229605213  90.0554114243 174.198478652   0.0000000000
## [6,] 542.058359064 288.699213957 176.2298003421  44.629402174 165.6357693696
##               [,6]
## [1,] 542.058359064
## [2,] 288.699213957
## [3,] 176.229800342
## [4,]  44.629402174
## [5,] 165.635769370
## [6,]   0.000000000

この値が @3tky さんの結果や国土地理院の公表データと一致していることを確認します。

市区町村役所の距離行列

続いて市区町村役所の距離行列を求めます。 こちらのデータも国土地理院が位置情報を整理しています。 ですがPDFなので、Rで扱う際にはデータを抽出する必要が生じます。

PDFファイルのダウンロードは以下のコードで行います。

df_link <-
  read_html("https://www.gsi.go.jp/KOKUJYOHO/center.htm") %>%
  html_nodes(css = "div.base_txt > div:nth-child(5) > table > tbody > tr > td > a") %>% {
    tibble::tibble(
      name = stringr::str_remove(html_text(.), "\\[.+\\]"),
      link = html_attr(., "href"))
  }
df_link$link %>%
  purrr::walk(
    ~ download.file(url = .x,
                    destfile = basename(.x))

RでPDFのデータ抽出を行うパッケージはいくつかありますが、今回は pdftools を使いました。 pdftools::pdf_text()によりテキストを抽出、若干血生臭い文字列処理を行いデータフレーム化します。 これらの処理を一括で実行する関数を書きました。

https://github.com/uribo/kuniezu/blob/22a17ac8ff3567095ca2a934bac9e3d6ccbc0820/data-raw/office_locaiton.R#L5-L59

リンク先のコード(関数部分)をコピーペーストで読み込んでください。 最終的には各都道府県のPDFを引数に与える gsi_office_extract() を実行することでデータ抽出が完了します。

# 茨城県の市区町村役所の位置情報
sf_pref08office <- 
  gsi_office_extract("ibaraki_heso.pdf")
sf_pref08office
## Simple feature collection with 45 features and 1 field
## geometry type:  POINT
## dimension:      XY
## bbox:           xmin: 139.745285034 ymin: 35.8577766418 xmax: 140.751113892 ymax: 36.8019447327
## CRS:            EPSG:4326
## # A tibble: 45 x 2
##    office                            geometry
##    <chr>                          <POINT [°]>
##  1 茨城県庁     (140.446670532 36.3413887024)
##  2 水戸市役所   (140.471664429 36.3658332825)
##  3 日立市役所   (140.650558472 36.5988883972)
##  4 土浦市役所   (140.204162598 36.0783348083)
##  5 古河市役所   (139.755004883 36.1783332825)
##  6 石岡市役所   (140.286941528 36.1905555725)
##  7 結城市役所    (139.876663208 36.305557251)
##  8 龍ケ崎市役所 (140.182220459 35.9116668701)
##  9 下妻市役所   (139.967498779 36.1844444275)
## 10 常総市役所   (139.993896484 36.0236129761)
## # … with 35 more rows

この位置情報データに対して、都道府県庁間の距離行列を求めた時と同じコードを実行することで市区町村役所の距離行列も求められます。 これらの処理も関数化しておきました。可視化と合わせてどうぞ。

# 距離行列を作成
st_distmatrix <- function(data, var) {
  res <-
    data %>%
    st_distance() %>%
    units::set_units(km)
  vars <-
    data %>%
    purrr::pluck(var)
  colnames(res) <- vars
  rownames(res) <- vars
  res
}
# ggplot2で描画するためのデータ整形。三角行列に変換して縦長のデータにします
matrix_to_longer <- function(data) {
  res_mt <-
    as.matrix(units::drop_units(data))
  res_mt[lower.tri(res_mt)] <- NA
  res_mt %>%
    as.data.frame() %>%
    tibble::rownames_to_column(var = "from") %>%
    tibble::as_tibble() %>%
    tidyr::pivot_longer(cols = seq.int(2, ncol(.)),
                        names_to = "to",
                        values_to = "dist") %>%
    dplyr::filter(!is.na(dist)) %>%
    dplyr::mutate_at(dplyr::vars(from),
                     list(~ forcats::fct_inorder(.))) %>%
    dplyr::mutate(to = forcats::fct_rev(forcats::fct_inorder(to)))
}
# ggplot2でのプロット
plot_distmatrix <- function(data) {
  data %>%
    ggplot(aes(from, to)) +
    geom_tile(aes(fill = dist), color = "white") +
    scale_fill_viridis_c() +
    guides(fill = guide_colorbar(title = "distance (km)")) +
    theme_bw(base_family = "IPAexGothic") +
    theme(
      axis.text.x = element_text(angle = 90),
      axis.ticks = element_blank(),
      axis.line = element_blank(),
      panel.border = element_blank(),
      panel.grid.major = element_line(color = '#eeeeee')
    )
}
st_distmatrix(sf_pref08office, "office") %>%
  matrix_to_longer() %>%
  plot_distmatrix()

f:id:u_ribo:20200509170948p:plain

Enjoy!