🤖

st_read()とread_sf()のどちらを使うか

2021/11/04に公開

はじめに

RをGISとして使うときの定番であるsfパッケージにはシェープファイルやGeoJSONを読み込むための関数としてst_read()read_sf()という関数が用意されている。この2つの関数について、どのような違いがあるのか、使い分けの必要はあるのか、といったことを記事にする。筆者としてはread_sf()を使っておいたほうが楽かな...という印象である。
本記事作成時に利用しているsfのバージョンは1.0-3である。

国土数値情報の行政区域を読み込む

st_read()read_sf()の動作確認のため、国土数値情報で提供される行政区域のシェープファイルを使用する。とりあえず実行してみて違いがあるか確認しよう。
まずはst_read()から。RMarkdownでコードチャンクを作成してそこで実行した場合、コードチャンクの下に読み込んだオブジェクトの情報が出力されているだろう。

# ShiftJISなので ENCODING=CP932 のオプションをつけないとダメ
sf_by_st_read <- sf::st_read("N03-180101_16_GML/N03-18_16_180101.shp",
                    options = c("ENCODING=CP932"))
output
## options:        ENCODING=CP932 
## Reading layer `N03-18_16_180101' from data source 
##   `/home/rstudio/R-Spatial-ChapA/N03-180101_16_GML/N03-18_16_180101.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 56 features and 5 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 136.7684 ymin: 36.27436 xmax: 137.7634 ymax: 36.98262
## Geodetic CRS:  JGD2011

次にread_sf()を実行する。この場合、先ほどのようにコードチャンクの下に読み込んだオブジェクトの情報は表示されない。これが違いの1つである。

# ShiftJISなので ENCODING=CP932 のオプションをつけないとダメ
sf_by_read_sf <- sf::read_sf("N03-180101_16_GML/N03-18_16_180101.shp",
                    options = c("ENCODING=CP932"))

実際のところread_sf()は内部ではst_read()を呼び出している(と思う。細かいのは未確認)。普通にst_read()を呼ぶときとread_sf()から呼ぶときとでは、デフォルトの引数の指定が異なる、というのが両者の違いになる。上記の、オブジェクトの情報を出力するしないは引数で与えるのがquiet = TRUEquiet = FALSEかで決まる。read_sf()quiet = FALSEとすると、次のようにオブジェクトの情報が出力されるようになる。

# quiet = FALSE をつけるとオブジェクト情報を出力する
sf::read_sf("N03-180101_16_GML/N03-18_16_180101.shp",
            options = c("ENCODING=CP932"),
            quiet = FALSE)
output
## options:        ENCODING=CP932 
## Reading layer `N03-18_16_180101' from data source 
##   `/home/rstudio/R-Spatial-ChapA/N03-180101_16_GML/N03-18_16_180101.shp' 
##   using driver `ESRI Shapefile'
## Simple feature collection with 56 features and 5 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 136.7684 ymin: 36.27436 xmax: 137.7634 ymax: 36.98262
## Geodetic CRS:  JGD2011

引数のデフォルトの指定値

st_read()read_sf()とで引数に与えるデフォルト値を整理したのが下の表である。このうちquietについてはすでに述べた。ほかの2つstringsAsFactorsas_tibbleについて、これから確認しよう。

引数 st_read() read_sf()
quiet TRUE FALSE
stringsAsFactors default.stringsAsFactors() FALSE
as_tibble FALSE TRUE

stringsAsFactors

Rユーザーがよく悩まされるstringsAsFactorsのデフォルト値は両者で異なる。st_read()default.stringsAsFactors()を参照し、read_sf()ではFALSEとなる。ただし、st_read()についてもRのバージョンが4.1.0以上であればFALSEとなるようである(st_read()のヘルプ参照)。stringsAsFactorsに関してはRのバージョン4.0.0以降ではデフォルトでFALSEに変更になっている(公式声明)ので、sfパッケージもその流れを汲んだ、ということになるのだろう。

as_tibble

この引数はRMarkdown上での使い勝手を左右する。個人的にはas_tibble = TRUE推奨である。RMarkdownのコードチャンクでsf_by_st_readsf_by_read_sfのそれぞれを呼び出して確認すると違いがよくわかる。

sf_by_st_readを呼び出した場合は、オブジェクト情報と最初の10行が出力されるだけだ。

# st_read()で読み込み。
# as_tibble = FALSE がデフォルト
sf_by_st_read
output
## Simple feature collection with 56 features and 5 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 136.7684 ymin: 36.27436 xmax: 137.7634 ymax: 36.98262
## Geodetic CRS:  JGD2011
## First 10 features:
##    N03_001 N03_002 N03_003 N03_004 N03_007                       geometry
## 1   富山県    <NA>    <NA>  富山市   16201 POLYGON ((137.1927 36.76204...
## 2   富山県    <NA>    <NA>  富山市   16201 POLYGON ((137.2309 36.76663...
## 3   富山県    <NA>    <NA>  高岡市   16202 POLYGON ((137.0972 36.77122...
## 4   富山県    <NA>    <NA>  高岡市   16202 POLYGON ((137.0532 36.81018...
## 5   富山県    <NA>    <NA>  高岡市   16202 POLYGON ((137.0753 36.80242...
## 6   富山県    <NA>    <NA>  高岡市   16202 POLYGON ((137.0454 36.81435...
## 7   富山県    <NA>    <NA>  高岡市   16202 POLYGON ((137.029 36.82186,...
## 8   富山県    <NA>    <NA>  魚津市   16204 POLYGON ((137.4181 36.85722...
## 9   富山県    <NA>    <NA>  氷見市   16205 POLYGON ((136.9958 36.86442...
## 10  富山県    <NA>    <NA>  氷見市   16205 POLYGON ((137.0099 36.89523...

一方sf_by_read_sfを呼び出した場合は、通常のデータフレームやtibbleのようにRMarkdown上で操作できるアレが表示される。

# read_sf()で読み込み。
# as_tibble = TRUE がデフォルト
sf_by_read_sf
output
## Simple feature collection with 56 features and 5 fields
## Geometry type: POLYGON
## Dimension:     XY
## Bounding box:  xmin: 136.7684 ymin: 36.27436 xmax: 137.7634 ymax: 36.98262
## Geodetic CRS:  JGD2011
## # A tibble: 56 x 6
##    N03_001 N03_002 N03_003 N03_004 N03_007                              geometry
##    <chr>   <chr>   <chr>   <chr>   <chr>                           <POLYGON [°]>
##  1 富山県  <NA>    <NA>    富山市  16201   ((137.1927 36.76204, 137.1918 36.761…
##  2 富山県  <NA>    <NA>    富山市  16201   ((137.2309 36.76663, 137.231 36.7666…
##  3 富山県  <NA>    <NA>    高岡市  16202   ((137.0972 36.77122, 137.0971 36.770…
##  4 富山県  <NA>    <NA>    高岡市  16202   ((137.0532 36.81018, 137.0531 36.810…
##  5 富山県  <NA>    <NA>    高岡市  16202   ((137.0753 36.80242, 137.0753 36.802…
##  6 富山県  <NA>    <NA>    高岡市  16202   ((137.0454 36.81435, 137.0453 36.814…
##  7 富山県  <NA>    <NA>    高岡市  16202   ((137.029 36.82186, 137.0291 36.8218…
##  8 富山県  <NA>    <NA>    魚津市  16204   ((137.4181 36.85722, 137.4187 36.857…
##  9 富山県  <NA>    <NA>    氷見市  16205   ((136.9958 36.86442, 136.9959 36.864…
## 10 富山県  <NA>    <NA>    氷見市  16205   ((137.0099 36.89523, 137.0096 36.894…
## # … with 46 more rows

記事にするとわかりづらいのでスクリーンショットを添付する。RMarkdown上で操作できるアレとはスクリーンショットのコレのことである。

RMarkdown上で操作できるアレ。as_tibble = TRUEで表示される。

sfパッケージを使う利点はGISのジオメトリ・地物をRでのデータフレームのように扱えて、tidyverseの恩恵にあずかれることにある。もちろんas_tibble = FALSEでもdplyr::filter()などの処理は有効なのだが、すでにみたようにRMarkdown上でインタラクティブに操作するアレは表示されない。アレを表示したい場合はdata.frame(st_by_st_read)tibble(sf_by_read_sf)とすれば可能である。ただしこの場合dplyr::filter()などの処理は有効だが、作図操作(たとえばggplot2::geom_sf()など)には注意が必要である。空間参照系の情報が消失するため、素直にやるとゆがんだ図になるだろう。軸には確かに北緯とか東経っぽい数字が並んでいるが、これはあくまで緯度経度っぽい数値であって、緯度経度の属性は含まれていない。

# tibble()する例
# 作図はできるけど、空間参照系がおかしくなる。
tibble(sf_by_st_read) %>% 
  dplyr::filter(N03_004 == "富山市") %>%
  ggplot2::ggplot() +
  ggplot2::geom_sf(aes(geometry = geometry)) # geometryを指定すれば作図可


緯度経度の値はあるけど属性はないのでゆがむ。国土数値情報(行政区域データ、富山県、平成30年度)(国土交通省)(https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v3_0.html) を加工して作成

tibble()でくくらなければゆがみもなくきれいな図になる。緯度経度の属性が保持されているためだ。ただし途中経過でデータフレームのインタラクティブ操作はできない。

# tibble()してない例
sf_by_st_read %>%
  dplyr::filter(N03_004 == "富山市") %>%
  ggplot2::ggplot() +
  ggplot2::geom_sf() # geometryは指定しなくても作図可


ゆがまなくてきれい。国土数値情報(行政区域データ、富山県、平成30年度)(国土交通省)(https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v3_0.html) を加工して作成

as_tibble = TRUEにしている場合はdplyrでの途中経過もアレで確認しながら作業が可能である(記事にするとわからないけど...)。もちろん最終的に出力される図は変わりない。

# as_tibble = TRUE のオブジェクトはアレでインタラクティブに確認可
sf_by_read_sf %>%
  dplyr::filter(N03_004 == "富山市") %>%
  ggplot2::ggplot() +
  ggplot2::geom_sf()


ゆがまなくてきれい。国土数値情報(行政区域データ、富山県、平成30年度)(国土交通省)(https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v3_0.html) を加工して作成

まとめ

st_read()read_sf()とは引数のデフォルト値が異なる。こだわりがなければread_sf()を使用したほうが便利なことが多いだろう。as_tibbleのデフォルトがTRUEであるのがその理由だ。TRUEのときRMarkdown上で操作できるアレが表示される。st_read()を使うときはas_tibbleTRUEで与えるかFALSEで与えるか試して自分の好みに合うほうを選ぶとよい。

Discussion