読者です 読者をやめる 読者になる 読者になる

SpatialPolygonsDataFrameをUnionするときのメモ

データ

使うのは前回のデータ。

library(rgdal)

f <- "C:\\path\\to\\gm-jpn-bnd_u_2_1"

l <- readOGR(f, layer = "polbnda_jpn", encoding = "UTF-8",verbose = TRUE)
glimpse(l@data)
#> Observations: 2,914
#> Variables: 9
#> $ f_code   (fctr) FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA001, FA0...
#> $ coc      (fctr) JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, ...
#> $ nam      (fctr) Hokkai Do, Hokkai Do, Hokkai Do, Hokkai Do, Hokkai Do, Hokkai Do, Hokkai Do, Hokkai Do, Hokkai Do, Hokkai Do, Hokka...
#> $ laa      (fctr) Sapporo Shi, Hakodate Shi, Otaru Shi, Asahikawa Shi, Muroran Shi, Kushiro Shi, Kushiro Shi, Obihiro Shi, Kitami Shi...
#> $ pop      (int) 1930496, 274485, 127224, 349057, 91276, 180160, -89999999, 169104, 123401, 9801, 87284, 38240, 23451, 174469, 37248,...
#> $ ypc      (int) 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 20...
#> $ adm_code (fctr) 01100, 01202, 01203, 01204, 01205, 01206, 01206, 01207, 01208, 01209, 01210, 01211, 01212, 01213, 01214, 01214, 012...
#> $ salb     (fctr) UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, UNK, ...
#> $ soc      (fctr) JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, JPN, ...

これは都道府県ごとのデータなので、単純にleaflet上にのっけるとこうなります。

leaflet() %>%
  addTiles() %>%
  addPolylines(data = l, color = "red")

f:id:yutannihilation:20151031175722p:plain:w400

ちょっと細かすぎる。これを都道府県(つまり、num)でまとめたい。

こういうちょっと高度な操作は、rgeosパッケージにあるみたいです。

gUnaryUnion()gUnionCascaded()がありますが、前者のほうが高度なのでGEOSがバージョン3.3.0以上であればこっちを使うように、とヘルプに書かれています。

library(rgeos)
l_union <- gUnaryUnion(l, id = as.character(l@data$nam))

leaflet() %>%
  addTiles() %>%
  addPolylines(data = l_union, color = "red")

f:id:yutannihilation:20151031180030p:plain:w400

ただし、注意点として、rgeosが処理すると元データにあったdataは消えてしまいます。残念ながらdataを保持したまま処理する方法はないので、必要な場合は手動で紐づける必要があります。

slotNames(l)
#> [1] "data"        "polygons"    "plotOrder"   "bbox"        "proj4string"
slotNames(l_union)
#> [1] "polygons"    "plotOrder"   "bbox"        "proj4string"

おまけ:splitしてから処理してあとでくっつける

けっきょく上のやり方に行きつきましたが、「splitしてくっつければいい?」と思ってつまづいたので後々のためにメモ。

SpatialPolygonsDataFrameは、ふつうのdata.frameと同じようにsplit()することができます。

l_split <- split(l, l@data$nam)

dataスロットもちゃんと保持されています。

slotNames(l_split[[1]])
#> [1] "data"        "polygons"    "plotOrder"   "bbox"        "proj4string"

で、これを別々にgUnaryUnion()してからくっつければいい?と思ってやってみたんですが、、

a <- lapply(l_split, gUnaryUnion)
l_union2 <- do.call(rbind, a)
#> Error in validObject(res) : 
#>   invalid class “SpatialPolygons” object: non-unique Polygons ID slot values

よくわかりませんがエラーがでます。これはなぜかというと、ポリゴンのIDという値がユニークである必要があるんですが、これが全部同じだからです。

sapply(a, function(x) x@polygons[[1]]@ID)[1:5]
 Aichi Ken  Akita Ken Aomori Ken  Chiba Ken  Ehime Ken 
       "1"        "1"        "1"        "1"        "1"

結局idを指定する必要があるので、(今回は)けっきょくsplit()しないほうが楽でした。

a <- lapply(l_split, function(x) gUnaryUnion(x, id = as.character(x@data$nam)))
l_union2 <- do.call(rbind, a)

おまけ2:48番目の都道府県

全然本筋と関係ありませんが、split()してデータをいじっていると、あることに気づきます。

length(l_split)
#> [1] 48

???

都道府県で分割したはずなのに、なぜか48個に分割されています...。と、とどうふけんって、47じゃないっけ!?

動揺を隠しきれず、names()してみます。

names(l_split)
#>  [1] "Aichi Ken"     "Akita Ken"     "Aomori Ken"    "Chiba Ken"     "Ehime Ken"    
#>  [6] "Fukui Ken"     "FUKUOKA"       "Fukuoka Ken"   "Fukushima Ken" "Gifu Ken"     
#> [11] "Gunma Ken"     "Hiroshima Ken" "Hokkai Do"     "Hyogo Ken"     "Ibaraki Ken"  
#> [16] "Ishikawa Ken"  "Iwate Ken"     "Kagawa Ken"    "Kagoshima Ken" "Kanagawa Ken" 
#> [21] "Kochi Ken"     "Kumamoto Ken"  "Kyoto Fu"      "Mie Ken"       "Miyagi Ken"   
#> [26] "Miyazaki Ken"  "Nagano Ken"    "Nagasaki Ken"  "Nara Ken"      "Niigata Ken"  
#> [31] "Oita Ken"      "Okayama Ken"   "Okinawa Ken"   "Osaka Fu"      "Saga Ken"     
#> [36] "Saitama Ken"   "Shiga Ken"     "Shimane Ken"   "Shizuoka Ken"  "Tochigi Ken"  
#> [41] "Tokushima Ken" "Tokyo To"      "Tottori Ken"   "Toyama Ken"    "Wakayama Ken" 
#> [46] "Yamagata Ken"  "Yamaguchi Ken" "Yamanashi Ken"

2行目に、我々が知らない48番目の都道府県がいます。その名もFUKUOKA。大文字になっているあたり別格さを感じさせます。

いったい何者なんだFUKUOKA...

(この隠された真実を知りすぎたために消されたりしなければ次回に続く)