Rで緯度経度から都道府県・市区町村を求める

@nozma さんが書いてくれた[記事](http://qiita.com/nozma/items/808bce2f496eabd50ff1)の俺俺改造記事です。nozmaさんの記事では「都道府県ごとにポリゴンをまとめる」という工程を行なっていますが、それを使わない方法、日本全国のポリゴンを直接利用する方法を紹介します。

なお国土数値情報の提供する行政区域データをRから呼び出すための[jpndistrict](https://github.com/uribo/jpndistrict)というパッケージがありますが、これは都道府県レベルのShapefileにしか対応していないので、全国shapefileは直接ダウンロードすることになります。今回は「2014年版 行政区域データ 全国のファイル」を使います。

余談ですが、jpndistrictパッケージはCRANに登録したものの、諸事情によりアーカイブされています。この問題を解決した次のバージョンではこの記事で取り上げる都道府県・市区町村判定の関数も取り込む予定です。

``` r
library(magrittr)
library(dplyr)
library(kokudosuuchi)
```

    ## このサービスは、「国土交通省　国土数値情報（カテゴリ名）」をもとに加工者が作成
    ## 以下の国土数値情報ダウンロードサービスの利用約款をご確認の上ご利用ください：
    ## 
    ## http://nlftp.mlit.go.jp/ksj/other/yakkan.html

``` r
# 2014年版 行政区域データ 全国のファイルをダウンロードして解凍
dl.url <- kokudosuuchi::getKSJURL(identifier = "N03") %>%
  dplyr::filter(year == 2014, areaCode == 0) %>% use_series(zipFileUrl)

download.file(dl.url,
              destfile = "N03-150101_GML.zip")
unzip("N03-150101_GML.zip")
```

ダウンロードしてきたshapefileを読み込みます。shapefileをはじめとした地理空間データをRで扱う際はsfパッケージを使うと大変楽です。

``` r
library(sf)
# Linking to GEOS 3.4.2, GDAL 2.1.2, proj.4 4.9.1
```

``` r
dfs.jp <- st_read("N03-20150101_GML")
# Reading layer `N03-15_37_150101' from data source `N03-20150101_37_GML/N03-15_37_150101.shp' using driver `ESRI Shapefile'
# converted into: POLYGON
# Simple feature collection with 669 features and 5 fields
# geometry type:  POLYGON
# dimension:      XY
# bbox:           xmin: 133.4465 ymin: 34.01229 xmax: 134.4475 ymax: 34.56485
# epsg (SRID):    NA
# proj4string:    +proj=longlat +ellps=GRS80 +no_defs
```

`find_city()`という関数を書きました。といってもほとんどnozmaさんのものと変わりません。対象のポリゴンと任意のポイントを指定し、ポイントがポリゴンに含まれるかを判定します。含まれる場合には市区町村コードと市区町村名を返します。

``` r
#' @param sp_polygon object of class sf, sfc or sfg
#' @param lon longitude
#' @param lat latitude
find_city <- function(sp_polygon = df, lon = lon, lat = lat) {
  
  which.row <- sf::st_contains(sp_polygon, sf::st_point(c(lon, lat)), sparse = FALSE) %>%  
    grep(TRUE, .)
  
  if (identical(which.row, integer(0)) == TRUE) {
    message("指定した座標がポリゴンに含まれません")
  } else {
  geos <- sp_polygon[which.row, ] %>%
    dplyr::mutate_if(is.factor, as.character) %>% 
    dplyr::mutate_at(dplyr::vars(N03_001:N03_004), dplyr::funs(dplyr::if_else(condition = is.na(.), true = "", false = .)))
  
    res <- tibble::data_frame(
    city_code = geos$N03_007,
    city_name = paste0(geos$N03_001, geos$N03_002, geos$N03_003, geos$N03_004)
  )
  
  return(res)
  }
}
```

``` r
find_city(dfs.jp, lon = 135.728965, lat = 35.039200)
```

    ## although coordinates are longitude/latitude, it is assumed that they are planar

    ## # A tibble: 1 × 2
    ##   city_code        city_name
    ##       <chr>            <chr>
    ## 1     26101 京都府京都市北区

``` r
find_city(dfs.jp, 139.884678, 35.626065)
```

    ## although coordinates are longitude/latitude, it is assumed that they are planar

    ## # A tibble: 1 × 2
    ##   city_code    city_name
    ##       <chr>        <chr>
    ## 1     12227 千葉県浦安市

``` r
find_city(dfs.jp, 139.523620, 35.495978)
```

    ## although coordinates are longitude/latitude, it is assumed that they are planar

    ## # A tibble: 1 × 2
    ##   city_code          city_name
    ##       <chr>              <chr>
    ## 1     14112 神奈川県横浜市旭区

一部の座標に関しては元のshapefileで抜け? があるためか失敗します。

``` r
find_city(dfs.jp, 139.7211411, 33.0182349)
# 指定した座標がポリゴンに含まれません
find_city(dfs.jp, 136.8231215, 34.8323039)
# 指定した座標がポリゴンに含まれません
```

``` r
system.time(find_city(dfs.jp, lon = 142.191237, lat = 27.0427396))
#    user  system elapsed 
#   3.676   0.223   3.917
```

全国のポリゴンを利用しているためか、やや時間がかかります...。市区町村名までの逆ジオコーディング手法として利用できるかとも考えましたが、件数の多い場合は別のサービス等を使うのが良さそうです。また、市区町村までいらないよ、という場合はnozmaさんの方法の通り`sf::st_combine()`によるポリゴンの結合を行うと良いでしょう。

jpndistrictパッケージを使う場合 (sf未対応・都道府県から検索)
------------------------------------------------------------

座標の位置する都道府県までは判明している場合、jpndistrictパッケージを使うともう少し素早く検索できます。

``` r
jpndistrict_find_city <- function(sp_polygon = df, lon = lon, lat = lat) {
  
  which.row <- sf::st_contains(sp_polygon, sf::st_point(c(lon, lat)), sparse = FALSE) %>%  
    grep(TRUE, .)
  
  if (identical(which.row, integer(0)) == TRUE) {
    message("指定した座標がポリゴンに含まれません")
  } else {
  geos <- sp_polygon[which.row, ]
  
    res <- tibble::data_frame(
    city_code = geos$city_code,
    city_name = paste0(geos$pref_name, geos$city_name_full)
  )
  
  return(res)
  }
}

jpndistrict::spdf_jpn_pref(26) %>% 
  st_as_sf(crs = 4326) %>% 
  jpndistrict_find_city(lon = 135.728965, lat = 35.039200)
```


    ## # A tibble: 1 × 2
    ##   city_code         city_name
    ##      <fctr>             <chr>
    ## 1     26101 京都府京都市 北区

``` r
jpndistrict::spdf_jpn_pref(12) %>% 
  st_as_sf(crs = 4326) %>% 
  jpndistrict_find_city(139.884678, 35.626065)
```

    ## # A tibble: 1 × 2
    ##   city_code    city_name
    ##      <fctr>        <chr>
    ## 1     12227 千葉県浦安市
    
    
``` r
system.time(jpndistrict::spdf_jpn_pref(33) %>% 
  st_as_sf(crs = 4326) %>% 
  jpndistrict_find_city(lon = 133.93602, lat = 34.665193))
#            user          system         elapsed 
# 0.0380000000000 0.0080000000000 0.0459999999998 
```