将多边形 json 坐标转换为 data.frame
transform polygon json coordinates into a data.frame
我想将一个数据框转换为另一个数据框。如果可能,在较少的命令中,使用 dplyr
或 tidyr
会很棒。
为了解析我使用的坐标列表 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。
这不是很好,但是对 strsplit
、gsub
和 unnest
的一些调用可以做很多事情:
- 按
]],
拆分允许我们分离多个多边形。
- 然后我们将它们分布在不同的行中。
- 创建
id
列可以在每个 code
中使用 row_number
轻松完成
- 再次拆分,在
],
上分离点对。
- 再次放在单独的行上。
- 删除所有
[
和 ]
。
- 在
,
上分隔以分隔 lon
和 lat
。
- 将它们放在单独的列中。
.
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
purrr
、dplyr
和jsonlite
解决方案:
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(我不得不在初始示例中编辑掉最终的 ]
)。
备注:
group_by
可以替换为 dplyr::rowwise
或(通过一些其他代码更改)替换为 purrr::by_row
- 习惯用法是遍历每个
code
,将 JSON 转换为坐标列表,遍历该列表并从每个多边形中创建一个日期框,并分配位置 ID
- 你想要的列名分配在三个地方:最开始的
group_by
(把code
变成a
),最里面的map_df
(为了lat
& lon
) 最后 id
是由最外层的 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)
我想将一个数据框转换为另一个数据框。如果可能,在较少的命令中,使用 dplyr
或 tidyr
会很棒。
为了解析我使用的坐标列表 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。
这不是很好,但是对 strsplit
、gsub
和 unnest
的一些调用可以做很多事情:
- 按
]],
拆分允许我们分离多个多边形。 - 然后我们将它们分布在不同的行中。
- 创建
id
列可以在每个code
中使用 - 再次拆分,在
],
上分离点对。 - 再次放在单独的行上。
- 删除所有
[
和]
。 - 在
,
上分隔以分隔lon
和lat
。 - 将它们放在单独的列中。
row_number
轻松完成
.
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
purrr
、dplyr
和jsonlite
解决方案:
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(我不得不在初始示例中编辑掉最终的 ]
)。
备注:
group_by
可以替换为dplyr::rowwise
或(通过一些其他代码更改)替换为purrr::by_row
- 习惯用法是遍历每个
code
,将 JSON 转换为坐标列表,遍历该列表并从每个多边形中创建一个日期框,并分配位置 ID - 你想要的列名分配在三个地方:最开始的
group_by
(把code
变成a
),最里面的map_df
(为了lat
&lon
) 最后id
是由最外层的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)