【问题标题】:transform polygon json coordinates into a data.frame将多边形 json 坐标转换为 data.frame
【发布时间】:2017-01-05 13:16:18
【问题描述】:

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

【问题讨论】:

标签: json r dataframe dplyr tidyr


【解决方案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

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

注意事项:

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

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)

【讨论】:

  • 我选择了这个解决方案,因为我发现它更容易在我的代码中使用。谢谢你。 :)
【解决方案2】:

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

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

【讨论】:

  • 我不知道unnest() 存在。但是将它与strsplit() 一起使用对我来说不合适,我不确定]], 是否始终是有效的分隔符。我真的很喜欢这个解决方案,我会进一步研究以适应我的真实数据。谢谢你:)
【解决方案3】:

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

【讨论】:

  • 谢谢@Floo0。我没有使用您的解决方案,因为它使用了reshape2,而且我从来不明白melt() 是如何工作的。但也许这是开始探索包裹的好时机。对不起! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-11
  • 2020-01-20
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多