cucumber flesh

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

sfオブジェクトを描画する方法まとめ: ggplot2::geom_sf()もあるよ

Rの作図パッケージとして人気なggplot2の時期バージョンの2.3.0が間も無くリリースされるそうです。ggplot2は前回の更新が2016年12月末のバージョン2.2.1なので、久しぶりのバージョンアップとなります。

バージョンアップに伴う変更点はこのページを見て欲しいですが、私としてはsfオブジェクトを描画するための新たな関数geom_sf()に触れずには要られません。これまでずっと開発版でのみ利用可能でしたが、やっとCRAN版でも利用できるようになります。(人に紹介するときはGitHubの説明からやったり面倒でもあった。)

... と思っていたらid: yutannihilationさんに先を越されてしまいました。

ggplot2 2.3.0(RC版)を使ってみた - Technically, technophobic.

notchained.hatenablog.com

同じ話題をしても仕方がないので、ここでは、ggplot2に実装されるgeom_sf()の紹介を兼ねて、sfパッケージにより作成されるsfオブジェクトを描画する方法を整理しようと思います。また、sfオブジェクトの可視化に祭して、私の知っているいくつかのtipsを紹介します。(私の持ち合わせる知識の範囲です。他にあればぜひ教えてください。)

公式のvignettesにもsfオブジェクトを描画する方法について整理されています。

https://cran.r-project.org/web/packages/sf/vignettes/sf5.html

sfオブジェクトを描画する際はまず、静的あるいは動的に描画するという目的によって使い分けます。静的な描画はRの標準グラフィックスに利用されるplot()、冒頭のggplot2などです。一方、動的な描画は、興味のある箇所を拡大したり、表示・非表示をユーザが切り替え可能な描画の方法です。具体的にはleafletplotlyがこの方法での選択肢となります。

私は、静的な出力の場合はgeom_sf()、動的にズームしたり動かしたい場合はmapview()というような使いわけをしています(少し前はmapviewではなくてleafletでしたが鞍替えしました)。

用意

作図用のデータとして、国土数値情報の提供する行政区域のデータ市区町村役場データを用います。このデータはjpndistrictによりRから取得可能です。

library(sf)
library(jpndistrict)
## Loading required package: jpmesh
## This package provide map data is based on the Digital Map 25000(Map Image) published by
## Geospatial Information Authorityof Japan (Approval No.603FY2017 information usage
## <http://www.gsi.go.jp>)
# 岡山県の行政区域データ
# この記事の中の岡山県のポリゴンデータを使った図は、国土地理院長の承認を得て、
# 同院発行の数値地図(国土基本情報)電子国土基本図(地図情報)を使用したものです (承認番号 平28情使、第603号)
pref_33 <- 
  jpn_pref(33)
head(pref_33)
## Simple feature collection with 6 features and 4 fields
## geometry type:  GEOMETRY
## dimension:      XY
## bbox:           xmin: 133.6025 ymin: 34.4173 xmax: 134.169 ymax: 35.30721
## epsg (SRID):    4326
## proj4string:    +proj=longlat +datum=WGS84 +no_defs
## # A tibble: 6 x 5
##   pref_code prefecture city_code city                             geometry
##   <chr>     <chr>      <chr>     <chr>                      <GEOMETRY [°]>
## 1 33        岡山県     33101     岡山市 北区 POLYGON ((133.9098 34.948, 1…
## 2 33        岡山県     33102     岡山市 中区 MULTIPOLYGON (((133.9747 34.…
## 3 33        岡山県     33103     岡山市 東区 MULTIPOLYGON (((133.9958 34.…
## 4 33        岡山県     33104     岡山市 南区 MULTIPOLYGON (((133.9109 34.…
## 5 33        岡山県     33202     倉敷市      MULTIPOLYGON (((133.6414 34.…
## 6 33        岡山県     33203     津山市      POLYGON ((134.0871 35.30721,…
# 岡山県内の市役所等のポイントデータ
df_office33 <- 
  jpn_admins(33)
## options:        ENCODING=cp932 
## Reading layer `P34-14_33' from data source `/private/var/folders/0x/mb63hycs4k30_7httqyxh2rr0000gn/T/RtmpVmQLFw/P34-14_33_GML/P34-14_33.shp' using driver `ESRI Shapefile'
## Simple feature collection with 105 features and 4 fields
## geometry type:  POINT
## dimension:      XY
## bbox:           xmin: 133.3315 ymin: 34.35497 xmax: 134.3596 ymax: 35.28274
## epsg (SRID):    NA
## proj4string:    +proj=longlat +ellps=GRS80 +no_defs
head(df_office33)
## Simple feature collection with 6 features and 4 fields
## geometry type:  POINT
## dimension:      XY
## bbox:           xmin: 133.8795 ymin: 34.65511 xmax: 134.039 ymax: 34.90654
## epsg (SRID):    NA
## proj4string:    +proj=longlat +ellps=GRS80 +no_defs
##   jis_code type           name                    address
## 1    33100    1     岡山市役所        岡山市北区大供1-1-1
## 2    33101    2       御津支所     岡山市北区御津金川1020
## 3    33101    2       建部支所    岡山市北区建部町福渡489
## 4    33103    2       瀬戸支所     岡山市東区瀬戸町瀬戸45
## 5    33101    2     鶴田連絡所 岡山市北区建部町角石谷2063
## 6    33101    1 岡山市北区役所        岡山市北区大供1-1-1
##                    geometry
## 1 POINT (133.9196 34.65511)
## 2  POINT (133.9354 34.7992)
## 3 POINT (133.9038 34.86932)
## 4  POINT (134.039 34.73388)
## 5 POINT (133.8795 34.90654)
## 6 POINT (133.9196 34.65511)

plot

sfパッケージには、作図関数のplot()の総称関数が用意されています。そのため、sfが生成する、sfg (simple feature geometry)、sfc (simple feature geometry list-column)、sf (simple feature)のいずれかのクラスに属するsfオブジェクトであれば、plot()を適用することで、難なく地物を描画することが可能です。

par(mfrow = c(1, 2))
# sfg
st_point(0:1) %>% 
  plot()
# sfc
st_sfc(st_point(0:1), 
       st_point(2:1)) %>% 
  plot(col = "red")

f:id:u_ribo:20180528070948p:plain

sfcを含んだsfオブジェクト(データフレームの変数 + geometryのようなもの)を描画すると全ての変数を対象に描画が行われます。

# 既定では全ての変数について描画を行う
plot(pref_33)

f:id:u_ribo:20180528070609p:plain

これは一旦の確認には良いですが、最終的な出力では一変数だけを出力することが多いかと思います。その際はst_geometry()をかまして地物情報だけを抽出し、sfcとして描画するか、特定列を参照した状態で描画を行うと良いでしょう。

# 地物情報だけを描画
st_geometry(pref_33) %>% 
  plot()
# 特定列だけの描画
# 凡例の表示のため、余白を調節します
par(oma = c(3, 3, 3, 6.5), mar = c(2, 1, 1, 2))
pref_33["city"] %>% 
  plot(family = "IPAPGothic")

f:id:u_ribo:20180528071544p:plain

ggplot2

次に今回の目玉となるggplot2でのgeom_sf()を使う方法です。基本的なことは冒頭にあげたyutannihilationさんの記事に書かれています。

library(ggplot2)

ggplot(pref_33) +
  geom_sf()

f:id:u_ribo:20180528071604p:plain

ggplot2に詳しい方ならご存知かと存じますが、ggplot2 では描画したいデータをggplot()の第一引数dataに指定します(ここでは岡山県の行政区域データ)。それを+で連結させ、どのように描画するかという際にgeom_*()を利用します。今回実装されるgeom_sf()はsfオブジェクトを描画する関数で、これまで散布図ならgeom_point()、棒グラフならgeom_bar()のように使い分けてきたように、sfオブジェクトであればgeom_sf()という塩梅となります。

ggplot(data = )geom_sf(data = )に渡す方法もあります。これは、描画したいオブジェクトが複数(例えばポリゴンとポイント)ある際に、それぞれのgeom_sf()で対象のデータを指定する時に、どのデータをどのにレイヤーに渡すかを区別させるために利用されます。

ggplot() +
  geom_sf(data = pref_33, aes(fill = city_code)) +
  geom_sf(data = df_office33, color = "white")

f:id:u_ribo:20180528071619p:plain

次のコードでも同じ図が得られますが、geom_sf()にどのデータが渡っているかがわかりにくいので、上記の方法が好みです。

ggplot(pref_33) +
  geom_sf(aes(fill = city_code)) +
  geom_sf(data = df_office33, color = "white")

より地図っぽく描画するには nozmaさんの記事にあるようにcoords_sf()theme_void()を使うと良いでしょう。

ggplot() +
  geom_sf(data = pref_33, aes(fill = city_code)) +
  # 緯度経度の線、ラベルを描画しない
  coord_sf(datum = NA) +
  # 背景色を白にする
  theme_void()

f:id:u_ribo:20180528071723p:plain

tmap

tmapは主題図を描くために適したパッケージですが、こちらもsfオブジェクトに対応しています。描画のための関数はqtm()およびtm_shape()です。

library(tmap)

qtm(pref_33)

f:id:u_ribo:20180528071956p:plain

tm_shape()ではmodeと呼ばれる機能があり、それを切り替えることで静的・動的な描画の切り替えが可能です。

# 結果は上の図と同じなので省略
tmap_mode("plot")

tm_shape(pref_33, projection = "longlat") + 
    tm_polygons()

インタラクティブに動かせる図を描画するにはモードをviewに切り替えます。動作の様子をgif画像で表示します。

tmap_mode("view")

tm_shape(pref_33) + 
  tm_fill("city_code", palette = sf.colors(20))

https://cdn-ak.f.st-hatena.com/images/fotolife/u/u_ribo/20180528/20180528073112.gif?1527460294

leaflet

leafletJavaScript製の地図描画ライブラリですが、Rに実装されたleafletパッケージはsfオブジェクトを描画し、ユーザが任意の箇所を拡大したり表示箇所を移動することが可能です。tmapmapviewの基礎として利用されているライブラリでもあります。

leafletでsfを表示するには、対象とするsfのgeometryの種類を把握した上で適した関数に渡す必要があります。すなわちポイントの場合は、addCircles()、ラインはaddPolylines()、ポリゴンはaddPolygons()といった具合です。

library(leaflet)

leaflet() %>% 
  addTiles() %>% 
  # ポイントの表示なのでaddCircles()
  # 日本のへそ公園の位置を表示
  addCircles(data = st_point(c(135, 35.0)) %>% 
               st_sfc() %>% 
               st_sf(crs = 4326))

f:id:u_ribo:20180528072339p:plain

leaflet() %>% 
  addTiles() %>% 
  # ポリゴンの表示
  addPolygons(data = pref_33)

f:id:u_ribo:20180528072414p:plain

mapview

ggplot2のようにオブジェクトを重ねていくことができますが、種類に応じて関数を分ける必要がある点や、ベースタイルの表示や表示の切り替えに別の関数を利用しなければならないという点でちょっと面倒です。そこで、もっとサクッと表示したいという時にmapviewが便利です。

ggplot2のように複数のオブジェクトを+演算子で重ねていくことができ、地物の種類も関係なくmapview()で済むので楽チンです(spオブジェクトにも対応します)。

library(mapview)

mapview(pref_33) 

地図描画のためのオプションも豊富で一押しです。

mapview(pref_33, 
        zcol = "city_code",
        legend = FALSE) +
  mapview(st_point(c(133.9196, 34.65511)),
          color = "red", 
          col.regions = "red")

https://cdn-ak.f.st-hatena.com/images/fotolife/u/u_ribo/20180528/20180528072806.gif?1527460146

plotly

最後に、leafletライブラリとは別のアプローチでsfを動的に可視化する方法としてplotlyの例です。こちらはまだ開発版の機能となりますが、plotlyの開発ブログ記事に書書かれているように、plotlyの特徴を活かした3Dでの表示や他の種類のグラフと組み合わせが可能なようです。

こちらは開発版の機能ですので、将来実装が変更される可能性があります。

remotes::install_github("ropensci/plotly")
library(plotly)

nc <- 
  sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
plot_geo(nc)

https://cdn-ak.f.st-hatena.com/images/fotolife/u/u_ribo/20180528/20180528074549.gif?1527461177

以上です。Enjoy!

何気ない関数・演算子の導入がプロジェクトを傷つけた

ちょっと前の話。私が手を加えたコードが動かないという相談を受けた。早速手元で試してみたが自分の環境では再現できている。確認のために再実行してもらうと確かに結果が違うようだ。なぜだろう。結論を書いてしまうと、問題は %<>% 演算子にあった。

%<>% 演算子、この演算子について知っている人はどのくらいいるだろうか。この演算子は、見た目も %>% と類似している。そう、 magrittr パッケージが提供するパイプ演算子の一種である。その働きは %>% 演算子と同様、パイプの左辺に与えられたオブジェクトに対し右辺で指定した関数に渡すものである。そして、その結果を左辺のオブジェクトに代入する。

library(magrittr)
x <- letters[1:3]

x %<>% toupper()
x
## [1] "A" "B" "C"

この演算子の何が良いのかというと、%>% を使った場合には次のように書く必要のあるコードを簡略化できることである。

x <- x %>% toupper()

パイプ処理の結果を元のオブジェクトに保存するのであれば、x <- x は冗長に思える。そこで %<>% を使う。一方で、それだけ、という話でもある。

%>% はtidyverseの処理の中で利用しているので知っている。しかし %<>% についてはその機能を知らない。知らない人からすると%<>%typoだと思って%>%に直してしまうかもしれない。そうすると私の意図した結果が得られないのもの納得できる。

私にとって当然であることがメンバーの常識であるとは限らない。dplyrtidyr パッケージの個々の関数について、その機能を把握するのにもある程度の時間がかかる。まずは個々の関数がどのパッケージから読み込まれているのかを理解させないといけない気もする。その場合には名前空間を指定してdplyr::mutate()のような書き方をしているが、package::function()が何を意味しているのか、名前空間とは何かがわかっていないと意味がない。これは自分も理解するのに時間が必要だった記憶がある。少なくとも本を読んだり誰かから説明を受けない限りは理解できなかっただろう。

tidyverseに含まれるパッケージやパイプ処理は大変便利であるが、それは初心者向きではない。

tidyverse is premature for you guys

(書いてない)

tidyverseの真価を知るには、Rで標準利用できる関数で手間のかかる処理をパイプ演算子と組み合わせて利用することで効果的になることを理解してもらうのが必要だ。

これは自分が感じていることであり、Hadley自身もそのようなことを言っていたのでちょっと安心した。

... チームで分析プロジェクトを進行していく際は、メンバー間で技術や知見の足並みを揃えることは大事だと考えているが、それは高い水準にするのでなく、今の状態で 共通認識として参加するメンバーが理解している範囲の水準にする方が良い気がしてきた。

パイプに加えて、先端的なパッケージや開発が盛んなパッケージの導入は便利だ。しかしそれは破滅の始まりになる危険性をはらんでいる。

#17: Dependencies.

ということを上の記事を読んで思った。ついつい忘れがちになってしまうが一度考える時間を設けたい。

質問お待ちしております!できればreprex使ってね 😸

最近、チームで分析プロジェクトを進行していることもあり、人のコードをみてコメントしたり、自分もみてもらう、というやりとりが増えてきました。メンバーの中で私は、どちらかといえば「R言語チョットデキル」人間で、時々発生するトラブルや質問について答えることもあります。

よくあるQ&A時の話ですが、回答に答える側になってみると質問してくる人に対してあれこれ言いたいことが出てきました。そんな気持ちを詠んだポエムです。Rの話になりますが、色々な言語で、強いてはプログラミング以外のことにでも言えるかもしれません。

Help me help you

一番に言いたいのは「 私はあなたの問題を解決したいと思っている 」ということ。個人的には、質問は自分の思いつかなかった手法や問題を提示してくれるので歓迎です(一プログラマとしての成長が望まれるので私にも見返りがある。感謝の気持ちもあります)。質問をためらわないでください(もちろん自力で解決できるに越したことはないし、落ち着いて見直したら・再度実行したら解決するもの、調べて済む問題は除く)。

問題に直面したあなたは、やや混乱しているかもしれません。ですが落ち着いて、問題がどこにあるのかを確認してみてください。文字の間違い、括弧や引用符の閉じ忘れ、などはよくある話です。そして質問してください。

あなたからの質問

注: ここでは、メールではなくてSlackのチャットやGitHub issuesでの質問を想定します。

質問はコードと一緒に

あなたからの質問が来ました。

「こんなエラーが出た」「これができない」

... お、おう。

これではちょっと困ってしまいます。あなたが何をしたいのか、何をしたら問題が発生してしまったのか、どこでつまづいているのか、詳細な情報とコードと共に示してくれると助かります。

個人的に、世の中、説明不足な質問で溢れているように感じます。説明が足りていないと、状況を把握しにくい、問題を突き詰めにくい、など悪いことが多いです。過多であることよりも不足していることが困ります。あれそれについての情報・状況を知らせてくださいと、あーだこーだ何度もやりとりを行うのはお互い良くないでしょう。最小限で問題が解決させるためには、あなたからの最初の情報提供が肝心です。

ありがちなパターン

  • 問題の途中から始めてしまう... 問題の箇所だけ、というのも困ります。ここでエラーになった、その情報は大事ですが、実は問題はもっと以前から、根本的な箇所で生じている可能性もあるのです。

コードはテキストで(ハイライトさせてくれるとさらに嬉しい)

次にあなたから実行したい処理の内容と問題の箇所を示したコードが示されました。みてみましょう。... ちょっと待って、もしかしてコンピュータの画面をスマートフォンで撮影した画像を貼り付けました? スクリーンキャプチャにしました? どうしてそんなことを!!!

コードを画像で撮影するのが好ましくないのは、画像をコピペしても問題の処理を再現することができないためです。再現、それは質問に答えるためにとても大事なことです。私が例え長年の経験と勘に優れたプログラマであったとしても、適当なコメントだけで質問に答えようとはしないでしょう。自分の考えが正しいかを確認するために、コードを自分の環境で試したいのです。しかし画像では、画像とエディタを相互に見比べながら画像に書かれている「コード」を書き起こす必要が生じてしまいます。ですので、コードは画像や文章ではなくて「コード」で示してください。ソースコードをファイルに保存してメールで添付してくれても構いません。

ソースコードですが、コピペで貼り付けました?それでも良い... い、いや、問題を説明している他の文章とは区別がつくようにしてください。お願いします。

ソースコードを記述するプログラミング言語は、数値と記号、文字列で表現されます。普通にみると見辛いです。これはあなたと一緒です。私たちはプログラミング言語を扱います。プログラミング言語自然言語と異なるのはあなたも知っていることでしょうが、SlackやGitHubではMarkdownと呼ばれるマークアップ言語(簡単な文字装飾機能と思ってください)が利用でき、その中にコードを他の文と区別させるための機能があります。

Creating and highlighting code blocks - User Documentation

加えて、シンタックスハイライトという文字に色をつける機能が用意されていて、これは多くの言語で利用できます。ソースコードの中の役割のようなものごとに異なる色が与えられ、その色を識別することで'なんとなく'読めるようになっているのです。普段シンタックスハイライトに慣れていると、装飾されていないコードを読むのは正直辛いのです。

Markdownでは` を三回繰り返しで示し、同じく ` の三回繰り返しで囲んだ部分がコードブロックとして扱われます。コードブロックをハイライトさせるために例えばRであれば次のようにします。

```r
library(reprex)

x <- mean(c(1, NA, 3:4))
mean(x)
# [1] NA
```

pythonであればrの部分をpythonとしてください。このブログにもシンタックスハイライトは実装されていて、上記のコードを鮮やかにすることができます。

library(reprex)

x <- mean(c(1, NA, 3:4))
mean(x)
# [1] NA

色をつける。単純なことですがこれなら少し読む気になりません?

reprexパッケージを使う

さて、いよいよRならではの話に入ってきます。これまでに説明した、質問へのお願いを実現するために reprex パッケージが便利です。パッケージの機能を説明した id:yutannihilation さんの記事がすでにありますが、ちょっと内容の追記と更新をしておきます。なおreprexは rep roducible ex ample からなる造語で、Romain Francoisによって名付けられました

notchained.hatenablog.com

Prepare Reproducible Example Code for Sharing • reprex

reprexGitHub issuesやStackOverflow、Slackでの再現可能なコードの例を用意してくれるパッケージおよびその関数名です。現在CRANに登録されているバージョンは0.1.2で、ここでもそのバージョンを利用しています。

reprex()ないで対象のコードを次のいずれかの形式で与えるか、ファイルを指定するかで、一時フォルダの中でコードが実行されます。RStudioを利用しているのであれば、専用のアドインも利用可能です(個人的にはこちらがおすすめ)。

reprex(mean(rnorm(10)))

reprex(input = "mean(rnorm(10))\n")

reprex(input = "my_reprex.R")

ここで肝心なのは、reprex()を実行している環境とは別の場所でコードが再実行されることと、コピーペーストでGitHub等のサービスにシンタックスハイライト可能なMarkdown形式で貼り付け可能なテキストが用意されることかと思います。

reprex()は、質問への回答者がコピーペーストで問題を再現できるように調整されています。ですのでreprex()は、対象のコードを実行して、読み込まれていないパッケージの関数やオブジェクトがある場合、出力もエラーメッセージを含んだものになります。これは実行したコードでは示されていないパッケージの読み込みやオブジェクトの作成がコードとは別の場所(例えばコンソールで実行しただけでコードには書かれていない)で行われていたことに起因します。人間のコピペだと、うっかり問題の箇所を見落としたり、情報を不足させる危険があるので、reprex()での実行環境を変えた再実行が効果的なのです。

ここで注意なのが、csvデータ等の読み込みです。read.csv()などを伴う処理を行う場合、パスを明確に指定しないとファイルがない、とエラーになることがあります。例えば現在の作業ディレクトリ(Rprojファイルがあるディレクトリ)で次のコードをreprex()に渡すと再現が失敗します。

d <- read.csv("iris.csv")
table(d$Species)
d <- read.csv("iris.csv")
#> Warning in file(file, "rt"): cannot open file 'iris.csv': No such file or
#> directory
#> Error in file(file, "rt"): cannot open the connection
table(d$Species)
#> Error in table(d$Species): object 'd' not found

ファイルの入出力を伴う場合はパスはフルパスで示すようにしましょう。

d <- read.csv("/home/rstudio/iris.csv")
table(d$Species)
#>
#>     setosa versicolor  virginica
#>         50         50         50

問題がデータではなくて処理にある場合、データはRに最初から用意されているデータやダミーデータを作成してくれると助かります(ローカルファイルの結果を示すことはできますが、再現にはファイルそのものが必要になるためです)。reprex公式では、irismtcarsが良いとされています。またデータはすべてでなくて構わない時があります。この時はhead()sample()を使って一部のデータを示してくれるだけで良いです。sample()などランダムに結果が異なる処理では、set.seed()により乱数の固定をすることも再現性の確保に必要になります。

Session Information

ソースコードの中身を追ったところ、コードには問題がないようです。ではどうして問題が発生しているのでしょう?

問題を深追いするために、あなたの利用環境について教えてもらう必要があります。RではsessionInfo()が用意されていて、これを実行するとコンピュータのOSや読み込んでいるパッケージの情報が出力されます。

sessionInfo()
#> R version 3.4.3 (2017-11-30)
#> Platform: x86_64-pc-linux-gnu (64-bit)
#> Running under: Debian GNU/Linux 9 (stretch)
#>
#> Matrix products: default
#> BLAS: /usr/lib/openblas-base/libblas.so.3
#> LAPACK: /usr/lib/libopenblasp-r0.2.19.so
#>
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=C             
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#>
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#>
#> loaded via a namespace (and not attached):
#>  [1] compiler_3.4.3  backports_1.1.2 magrittr_1.5    rprojroot_1.3-2
#>  [5] tools_3.4.3     htmltools_0.3.6 yaml_2.1.16     Rcpp_0.12.15   
#>  [9] stringi_1.1.6   rmarkdown_1.8   knitr_1.19      stringr_1.2.0  
#> [13] digest_0.6.15   evaluate_0.10.1

パッケージの違いを追うのにこの情報が必要なことがあります。さらに専用のパッケージ、 sessioninfo が用意されていて、こっちを使ってもらっても良いです(こっちの方が良いかな)。sessioninfo の出力の例です。

sessioninfo::session_info()
#> ─ Session info ──────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 3.4.3 (2017-11-30)
#>  os       Debian GNU/Linux 9 (stretch)
#>  system   x86_64, linux-gnu           
#>  ui       X11                         
#>  language (EN)                        
#>  collate  en_US.UTF-8                 
#>  tz       UTC                         
#>  date     2018-02-28                  
#>
#> ─ Packages ──────────────────────────────────────────────────────────────
#>  package     * version    date       source                      
#>  backports     1.1.2      2017-12-13 CRAN (R 3.4.3)              
#>  clisymbols    1.2.0      2017-05-21 CRAN (R 3.4.3)              
#>  digest        0.6.15     2018-01-28 CRAN (R 3.4.3)              
#>  evaluate      0.10.1     2017-06-24 CRAN (R 3.4.3)              
#>  htmltools     0.3.6      2017-04-28 CRAN (R 3.4.3)              
#>  knitr         1.19       2018-01-29 CRAN (R 3.4.3)              
#>  magrittr      1.5        2014-11-22 CRAN (R 3.4.3)              
#>  Rcpp          0.12.15    2018-01-20 CRAN (R 3.4.3)              
#>  rmarkdown     1.8        2017-11-17 CRAN (R 3.4.3)              
#>  rprojroot     1.3-2      2018-01-03 CRAN (R 3.4.3)              
#>  sessioninfo   1.0.0      2017-06-21 CRAN (R 3.4.3)              
#>  stringi       1.1.6      2017-11-17 CRAN (R 3.4.3)              
#>  stringr       1.2.0      2017-02-18 CRAN (R 3.4.3)              
#>  withr         2.1.1.9000 2018-02-28 Github (r-lib/withr@5d05571)
#>  yaml          2.1.16     2017-12-12 CRAN (R 3.4.3)

sessionInfo()を含めないのはなぜ?

id:yutannihilation さんの記事の中で

session infoは含めない!

と書かれています。うーむ。これについて、私も最初ユタニさん同様、どうしてだろうと思いました。

ですが、sessionInfo()の情報が必要になるのは、問題がコードにない時だろうと思います。問題がコードにあるのであればsessionInfo()は余分な情報となります。

sessionInfo()はコードだけで問題解決ができない時、追加の情報として求めれば良いのだろうと考えています。

reprex 0.2.0 が良い感じ

reprex パッケージの最新版は 0.1.2であると述べましたが、おそらく次期バージョンの 0.2.0 ではさらに使いやすく、より便利になっています。問題がなければこちらのバージョンを先取りし、GitHubからインストールして使うのを勧めます。

インストールは次のコードの実行で行われます。

install.packages("githubinstall")
githubinstall::githubinstall("reprex")

0.2.0では次の画像のような出力になります。reprexを使ったこととそのバージョンも示されていて良いですね。

f:id:u_ribo:20180301073429p:plain

ちなみにパッケージは現在は tidyverseリポジトリに属するようになっています。

それでは、良い質問と良い回答を! Enjoy!

(あとでちょっと追記するかも)