2016-09-28 13 views
7

Nie wiem, jak poprawnie przekonwertować moje dane JSON na użyteczną ramkę danych. To przykładowe dane, które przedstawia strukturę moich danych:Jak przekonwertować złożone dane JSON w pojedynczą ramkę danych?

{ 
"data":[ 
{"track":[ 
{"time":"2015","midpoint":{"x":6,"y":8},"realworld":{"x":1,"y":3},"coordinate":{"x":16,"y":38}}, 
{"time":"2015","midpoint":{"x":6,"y":8},"realworld":{"x":1,"y":3},"coordinate":{"x":16,"y":37}}, 
{"time":"2016","midpoint":{"x":6,"y":9},"realworld":{"x":2,"y":3},"coordinate":{"x":16,"y":38}} 
]}, 
{"track":[ 
{"time":"2015","midpoint":{"x":5,"y":9},"realworld":{"x":-1,"y":3},"coordinate":{"x":16,"y":38}}, 
{"time":"2015","midpoint":{"x":5,"y":9},"realworld":{"x":-1,"y":3},"coordinate":{"x":16,"y":38}}, 
{"time":"2016","midpoint":{"x":5,"y":9},"realworld":{"x":-1,"y":3},"coordinate":{"x":16,"y":38}}, 
{"time":"2015","midpoint":{"x":3,"y":15},"realworld":{"x":-9,"y":2},"coordinate":{"x":17,"y":38}} 
]}, 
{"track":[ 
{"time":"2015","midpoint":{"x":6,"y":7},"realworld":{"x":-2,"y":3},"coordinate":{"x":16,"y":39}} 
]}]} 

Mam wiele ścieżek i chciałbym zestaw danych powinien wyglądać tak:

track time midpoint realworld coordinate 
1 
1 
1 
2 
2 
2 
2 
3 

tej pory mam to :

json_file <- "testdata.json" 
data <- fromJSON(json_file) 
data2 <- list.stack(data, fill=TRUE) 

teraz to wychodzi tak:

data output

Jak mogę uzyskać to we właściwym formacie?

Odpowiedz

4

Dodaj parametr flatten = TRUE podczas czytania z fromJSON. Otrzymasz listę zagnieżdżoną, zawierającą najgłębszy poziom listę trzech ramek danych. Zastosowanie:

library(jsonlite) 
# read the json 
jsondata <- fromJSON(txt, flatten = TRUE) 

# bind the dataframes in the nested 'track' list together  
dat <- do.call(rbind, jsondata$data$track) 

# add a track variable 
dat$track <- rep(1:length(jsondata$data$track), sapply(jsondata$data$track, nrow)) 

otrzymujemy:

> dat 
    time midpoint.x midpoint.y realworld.x realworld.y coordinate.x coordinate.y track 
1 2015   6   8   1   3   16   38  1 
2 2015   6   8   1   3   16   37  1 
3 2016   6   9   2   3   16   38  1 
4 2015   5   9   -1   3   16   38  2 
5 2015   5   9   -1   3   16   38  2 
6 2016   5   9   -1   3   16   38  2 
7 2015   3   15   -9   2   17   38  2 
8 2015   6   7   -2   3   16   39  3 

Innym krótsza podejście wykorzystuje jsonlite w połączeniu z rbindlist pakiecie data.table:

library(jsonlite) 
library(data.table) 
# read the json 
jsondata <- fromJSON(txt, flatten = TRUE) 
# bind the dataframes in the nested 'track' list together 
# and include an id-column at the same time 
dat <- rbindlist(jsondata$data$track, idcol = 'track') 

lub z bind_rows z opakowania dplyr w w podobny sposób:

library(dplyr) 
dat <- bind_rows(jsondata$data$track, .id = 'track') 

Używane dane:

txt <- '{ 
"data":[ 
{"track":[ 
{"time":"2015","midpoint":{"x":6,"y":8},"realworld":{"x":1,"y":3},"coordinate":{"x":16,"y":38}}, 
{"time":"2015","midpoint":{"x":6,"y":8},"realworld":{"x":1,"y":3},"coordinate":{"x":16,"y":37}}, 
{"time":"2016","midpoint":{"x":6,"y":9},"realworld":{"x":2,"y":3},"coordinate":{"x":16,"y":38}} 
]}, 
{"track":[ 
{"time":"2015","midpoint":{"x":5,"y":9},"realworld":{"x":-1,"y":3},"coordinate":{"x":16,"y":38}}, 
{"time":"2015","midpoint":{"x":5,"y":9},"realworld":{"x":-1,"y":3},"coordinate":{"x":16,"y":38}}, 
{"time":"2016","midpoint":{"x":5,"y":9},"realworld":{"x":-1,"y":3},"coordinate":{"x":16,"y":38}}, 
{"time":"2015","midpoint":{"x":3,"y":15},"realworld":{"x":-9,"y":2},"coordinate":{"x":17,"y":38}} 
]}, 
{"track":[ 
{"time":"2015","midpoint":{"x":6,"y":7},"realworld":{"x":-2,"y":3},"coordinate":{"x":16,"y":39}} 
]}]}' 
+1

IMO to byłby bardzo pouczające pozostawić w swoim iteracji do ostatecznego rozwiązania, ale efekt końcowy jest ++ eleganckie. – hrbrmstr

+0

@hrbrmstr thx :-), ale co masz na myśli mówiąc "zostawić w swoich iteracjach ostateczne rozwiązanie" *? – Jaap

+0

argh, masz rację. źle przeczytałem ostateczną wersję i myślałem, że usunąłeś sapply (było inaczej sformatowane). Teraz próbuję dowiedzieć się, dlaczego 'purrr :: flatten_df()' - które po prostu naprawdę nazywa się 'dplyr :: bind_rows()' - nie zadziała w tym przypadku. Udało mi się również przekodować R za pomocą niektórych połączeń typu "purrr", więc był to dobry post całego PO (trzeba złożyć kilka spraw GH). – hrbrmstr

2

odpowiedź sahil (jeśli nie jest już usunięty) jest mylące, ponieważ stream_in jest ndjson i nie masz ndjson. Trzeba tylko nieco rozwikłać listę zagnieżdżoną. Myślę, że dodaje się można nawet mniejszy, ale to był szybki, bezpośredni atak Hack:

library(jsonlite) 
library(purrr) 
library(readr) 

dat <- fromJSON(txt, simplifyVector=FALSE) # read in your JSON 
map(dat$data, "track") %>%     # move past the top-level "data" element and iterate over the "track"s 
    map_df(function(track) {     # iterate over each element of "track" 
    map_df(track, ~as.list(unlist(track))) # convert it to a data frame 
    }, .id="track") %>%      # add in the track "id" 
    type_convert()       # convert mangled types 
## # A tibble: 8 × 8 
## track time midpoint.x midpoint.y realworld.x realworld.y coordinate.x coordinate.y 
## <int> <int>  <int>  <int>  <int>  <int>  <int>  <int> 
## 1  1 2016   6   9   2   3   16   38 
## 2  1 2016   6   9   2   3   16   38 
## 3  1 2016   6   9   2   3   16   38 
## 4  2 2015   3   15   -9   2   17   38 
## 5  2 2015   3   15   -9   2   17   38 
## 6  2 2015   3   15   -9   2   17   38 
## 7  2 2015   3   15   -9   2   17   38 
## 8  3 2015   6   7   -2   3   16   39 

to również pozostawia nam godnych typów kolumn, choć może chcesz użyć parametru col_types do readr::type_convert aby włączyć time do wektora znaków.

Alternatywnie:

library(jsonlite) 
library(purrr) 
library(tibble) 

dat <- fromJSON(txt, flatten=TRUE) # read in your JSON 
map_df(dat$data$track, as_tibble, .id="track") 
Powiązane problemy