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

时间:2016-08-29 13:22:29

标签: json r dataframe dplyr tidyr

我想将数据帧转换为另一个数据帧。如果可能,在较少的命令中,使用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]]]

输入数据描述:

  • code包含邮政编码
  • polygon包含一个或多个由其纬度 - 经度点对定义的多边形

想要输出:

> 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。

3 个答案:

答案 0 :(得分:6)

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::rowwisepurrr::by_row
  2. 替换(以及其他一些代码更改)
  3. 成语是迭代每个code,将JSON转换为坐标列表,遍历该列表并从每个多边形中生成一个日期框,并为其指定位置ID。
  4. 您想要的列名称分配在三个位置:初始group_by(将code转变为a),最里面的map_dflat }&amp; lon)以及最后由id自动创建的map_df
  5. 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)
    

答案 1 :(得分:2)

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

  • ]],分割允许我们分隔多个多边形。
  • 然后我们将它们分散在不同的行上。
  • 可以使用id
  • 中的row_number轻松创建code
  • 再次拆分,在],上分隔点对。
  • 再次穿上单独的行。
  • 删除所有[]
  • 单独,分隔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

答案 2 :(得分:1)

我认为在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