2016-08-29 19 views
6

Tôi muốn chuyển đổi một khung dữ liệu vào một khung dữ liệu khác. Nếu có thể, trong các lệnh ít hơn, sử dụng dplyr hoặc tidyr sẽ là tuyệt vời.biến đổi đa giác json tọa độ thành một data.frame

Để phân tích cú pháp danh sách tọa độ tôi đã sử dụng library(rjson), phần này là OK, nhưng tôi không thể thao tác thêm danh sách để nhận kết quả của mình.

Nếu bạn có thể tránh sử dụng bất kỳ tuyên bố for sẽ là tuyệt vời, nhưng giải pháp nào là tốt miễn là nó giải quyết vấn đề :)

Input:

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

Input mô tả dữ liệu:

  • cột code chứa mã bưu chính
  • cột.210 chứa một hoặc nhiều đa giác xác định bởi cặp vĩ độ-kinh độ của họ về điểm

Output muốn:

> 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 

Tôi muốn âm mưu muốn data.frame sử dụng ggplot.

+2

có lẽ bạn có thể finagle này để làm việc: https://cran.r-project.org/web/packages/tidyjson /vignettes/introduction-to-tidyjson.html – MichaelChirico

+0

Không thể tìm cách sử dụng 'tidyjson' với mảng/thuộc tính chưa đặt tên. Làm thế nào bạn sẽ sử dụng 'spread_values' trong trường hợp này? – Rentrop

Trả lời

6

purrr, dplyrjsonlite giải pháp:

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 

này có thêm lợi ích của việc chứng thực dữ liệu đa giác kể từ ví dụ của bạn ha [ds] JSON không hợp lệ (tôi đã phải chỉnh sửa ] cuối cùng trong ví dụ ban đầu).

GHI CHÚ:

  1. Các group_by có thể được thay thế bằng dplyr::rowwise hoặc (với một số thay đổi mã khác) bởi purrr::by_row
  2. Các thành ngữ là để lặp qua từng code, chuyển đổi JSON vào một danh sách các tọa độ, lặp qua danh sách đó và tạo khung ngày trong mỗi đa giác và gán ID vị trí cho nó.
  3. Các tên cột bạn muốn được giao ở ba nơi: ban đầu group_by (để biến code vào a) thì trong cùng map_df (ví lat & lon) và cuối cùng id đó là tính năng tự động tạo ra bởi ngoài cùng map_df.

rowwise phiên bản:

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 phiên bản:

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) 
+0

Tôi đã chọn giải pháp này vì tôi thấy dễ sử dụng hơn trong mã của tôi. Cảm ơn bạn. :) – Costin

2

Đây không phải là đẹp, nhưng một số cuộc gọi đến strsplit, gsub, và unnest có thể làm khá một chút:

  • Splitting bởi ]], cho phép chúng ta nhiều đa giác riêng biệt.
  • Sau đó, chúng tôi sẽ trải đều các hàng riêng biệt.
  • Tạo cột id có thể dễ dàng được thực hiện với row_number trong mỗi tách code
  • một lần nữa, trên ], để tách các cặp điểm.
  • Đặt lại các hàng riêng biệt.
  • Xóa tất cả [].
  • Riêng biệt trên , để tách riêng lonlat.
  • Đặt các cột đó vào các cột riêng biệt.

.

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 
+0

Tôi không biết rằng 'unnest()' tồn tại. Nhưng việc sử dụng nó với 'strsplit()' không phải là ok đối với tôi, tôi không chắc chắn rằng ']],' luôn là một dấu tách hợp lệ. Tôi thực sự thích giải pháp này và tôi sẽ xem xét thêm để thích ứng với dữ liệu thực của tôi. Cảm ơn bạn :) – Costin

1

Tôi nghĩ rằng có một khung đóng cửa quá nhiều trong df $ đa giác [2].Nếu điều đó được lấy ra, bạn có thể làm như sau:

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) 

nào mang đến cho bạn:

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 
+0

Cảm ơn bạn @ Floo0. Tôi đã không sử dụng giải pháp của bạn bởi vì nó sử dụng 'reshape2' và tôi chưa bao giờ hiểu cách' melt() 'hoạt động. Nhưng có lẽ đây là dịp tốt để bắt đầu khám phá gói. Lấy làm tiếc! :) – Costin

Các vấn đề liên quan