将多边形 json 坐标转换为 data.frame

transform polygon json coordinates into a data.frame

我想将一个数据框转换为另一个数据框。如果可能,在较少的命令中,使用 dplyrtidyr 会很棒。

为了解析我使用的坐标列表 library(rjson),这部分没问题,但我无法进一步操作列表来获得我的结果。

如果你能避免使用任何 for 语句就好了,但只要能解决问题,任何解决方案都是好的 :)

输入:

df <- data.frame(code = c("12000", "89000"),
                 polygon = c("[[[11,12], [13,14], [15,16]], [[21, 22], [23,24], [25,26]]]",
                             "[[[81,82], [83,84], [85,86]]]"))
df

> df
   code                                                     polygon
1 12000 [[[11,12], [13,14], [15,16]], [[21, 22], [23,24], [25,26]]]
2 89000                               [[[81,82], [83,84], [85,86]]]

输入数据说明:

想要的输出:

> wanted
       a lon lat id
1  12000  11  12  1
2  12000  13  14  1
3  12000  15  16  1
4  12000  21  22  2
5  12000  23  24  2
6  12000  25  26  2
7  89000  81  82  1
8  89000  83  84  1
9  89000  85  86  1

我想使用 ggplot 绘制想要的 data.frame。

这不是很好,但是对 strsplitgsubunnest 的一些调用可以做很多事情:

  • ]], 拆分允许我们分离多个多边形。
  • 然后我们将它们分布在不同的行中。
  • 创建 id 列可以在每个 code
  • 中使用 row_number 轻松完成
  • 再次拆分,在 ], 上分离点对。
  • 再次放在单独的行上。
  • 删除所有 []
  • , 上分隔以分隔 lonlat
  • 将它们放在单独的列中。

.

df %>% 
  mutate(polygon = strsplit(polygon, ']],')) %>% 
  unnest() %>% 
  group_by(code) %>% 
  mutate(id = row_number(),
         polygon = strsplit(polygon, '],')) %>% 
  unnest() %>% 
  mutate(polygon = gsub(']|\[', '', polygon),
         polygon = strsplit(polygon, ','),
         lon = sapply(polygon, '[', 1),
         lat = sapply(polygon, '[', 2)) %>% 
  select(-polygon)
Source: local data frame [9 x 4]
Groups: code [2]

   code    id   lon   lat
  <chr> <int> <chr> <chr>
1 12000     1    11    12
2 12000     1    13    14
3 12000     1    15    16
4 12000     2    21    22
5 12000     2    23    24
6 12000     2    25    26
7 89000     1    81    82
8 89000     1    83    84
9 89000     1    85    86

我认为 df$polygon[2] 中的右括号太多了。如果删除了,您可以执行以下操作:

require(jsonlite)
require(reshape2)
parse_json <- function(polygon, code){
  molten <- melt(fromJSON(polygon))
  lat <- molten[which(molten$Var3==1), "value"]
  lon <- molten[which(molten$Var3==2), "value"]
  id <- molten[which(molten$Var3==1), "Var1"]
  data.frame(code, lat, lon, id)
}

dat_raw <- mapply(parse_json, df$polygon, df$code, SIMPLIFY = FALSE, USE.NAMES = FALSE)
do.call(rbind, dat_raw)

这给你:

   code lat lon id
1 12000  11  12  1
2 12000  21  22  2
3 12000  13  14  1
4 12000  23  24  2
5 12000  15  16  1
6 12000  25  26  2
7 89000  81  82  1
8 89000  83  84  1
9 89000  85  86  1

purrrdplyrjsonlite解决方案:

df <- data.frame(code = c("12000", "89000"),
                 polygon = c("[[[11,12], [13,14], [15,16]], [[21, 22], [23,24], [25,26]]]",
                             "[[[81,82], [83,84], [85,86]]]"),
                 stringsAsFactors=FALSE)

library(purrr)
library(dplyr)
library(jsonlite)

make_coords <- function(x) {
  fromJSON(x$polygon, simplifyMatrix=FALSE) %>% 
  map_df(~map_df(., ~setNames(as.data.frame(as.list(.)), c("lat", "lon"))), .id="id")
} 

group_by(df, a=code) %>% 
  do(make_coords(.)) %>%
  ungroup() %>% 
  select(a, lat, lon, id)
## # A tibble: 9 x 4
##       a   lat   lon    id
##   <chr> <int> <int> <chr>
## 1 12000    11    12     1
## 2 12000    13    14     1
## 3 12000    15    16     1
## 4 12000    21    22     2
## 5 12000    23    24     2
## 6 12000    25    26     2
## 7 89000    81    82     1
## 8 89000    83    84     1
## 9 89000    85    86     1

这有验证多边形数据的额外好处,因为您的示例 ha[ds] 无效 JSON(我不得不在初始示例中编辑掉最终的 ])。

备注:

  1. group_by 可以替换为 dplyr::rowwise 或(通过一些其他代码更改)替换为 purrr::by_row
  2. 习惯用法是遍历每个 code,将 JSON 转换为坐标列表,遍历该列表并从每个多边形中创建一个日期框,并分配位置 ID
  3. 你想要的列名分配在三个地方:最开始的group_by(把code变成a),最里面的map_df(为了lat & lon) 最后 id 是由最外层的 map_df.
  4. 自动创建的

rowwise版本:

make_coords2 <- function(x) {
  fromJSON(x$polygon, simplifyMatrix=FALSE) %>% 
    map_df(~map_df(., ~setNames(as.data.frame(as.list(.)), c("lat", "lon"))), .id="id") %>% 
    mutate(a=x$a)
}

select(df, a=code, polygon) %>% 
  rowwise() %>% 
  do(make_coords2(.)) %>%
  ungroup() %>% 
  select(a, lat, lon, id)

by_row版本:

make_coords3 <- function(x) {
  fromJSON(x$polygon, simplifyMatrix=FALSE) %>% 
    map_df(~map_df(., ~setNames(as.data.frame(as.list(.)), c("lat", "lon"))), .id="id")
}

select(df, a=code, polygon) %>% 
  by_row(make_coords3, .collate="rows") %>% 
  select(a, lat, lon, id)