У меня есть довольно длинный список JSON, который я хочу преобразовать во фрейм данных. Я надеюсь, что кто-нибудь поможет мне разобраться.
{"body":{"overall_standings":{"years":[{"standings":null,"id":"2006"},{"standings":null,"id":"2007"},{"standings":null,"id":"2008"},{"standings":null,"id":"2009"},{"standings":null,"id":"2010"},{"standings":null,"id":"2011"},{"standings":{"teams":[{"Pitching":{"roto_points":"47.0","categories":[{"abbr":"S","roto_points":"91","value":"New York Yankees","diff":"9","rank":5},{"roto_points":"90","value":"New York Yankees","abbr":"W","diff":"7","rank":7},{"roto_points":"1383","value":"New York Yankees","abbr":"K","diff":"10","rank":4},{"abbr":"WHIP","roto_points":"1.2451","value":"New York Yankees","diff":"10","rank":4},{"abbr":"ERA","roto_points":"3.685","value":"New York Yankees","diff":"11","rank":3}]},"Total":{"behind":"0.0","roto_points":"98.0","diff":"-4.0","rank":1},"order":1,"name":"New York Yankees","Batting":{"roto_points":"51.0","categories":[{"abbr":"OBP","roto_points":"0.3371","value":"New York Yankees","diff":"7","rank":7},{"roto_points":"905","value":"New York Yankees","abbr":"RBI","diff":"10","rank":4},{"roto_points":"955","value":"New York Yankees","abbr":"R","diff":"12","rank":2},{"abbr":"SB","roto_points":"183","value":"New York Yankees","diff":"13","rank":1},{"abbr":"HR","roto_points":"247","value":"New York Yankees","diff":"9","rank":5}]},"id":"2"},{"Pitching":{"roto_points":"44.5","categories":[{"abbr":"S","roto_points":"105","value":"Los Angeles Dodgers","diff":"12","rank":2},{"roto_points":"96","value":"Los Angeles Dodgers","abbr":"W","diff":"10.5","rank":3},{"roto_points":"1410","value":"Los Angeles Dodgers","abbr":"K","diff":"11","rank":3},{"abbr":"WHIP","roto_points":"1.2798","value":"Los Angeles Dodgers","diff":"3","rank":11},{"abbr":"ERA","roto_points":"3.810","value":"Los Angeles Dodgers","diff":"8","rank":6}]},"Total":{"behind":"4.0","roto_points":"94.0","diff":"0.0","rank":2},"order":2,"name":"Los Angeles Dodgers","Batting":{"roto_points":"49.5","categories":[{"abbr":"OBP","roto_points":"0.3446","value":"Los Angeles Dodgers","diff":"11","rank":3},{"roto_points":"907","value":"Los Angeles Dodgers","abbr":"RBI","diff":"11","rank":3},{"roto_points":"909","value":"Los Angeles Dodgers","abbr":"R","diff":"9","rank":5},{"abbr":"SB","roto_points":"152","value":"Los Angeles Dodgers","diff":"11","rank":3},{"abbr":"HR","roto_points":"234","value":"Los Angeles Dodgers","diff":"7.5","rank":6}]},"id":"1"}]},"id":"2012"}]}}}
После запятой список продолжается до id 2017.
{"standings":{"teams":[{"Pitching":{"roto_points":"40.5","categories":[{"abbr":"S","roto_points":"100","value":"Los Angeles
Заранее спасибо!
Было бы действительно полезно узнать, что вы пробовали до сих пор и чего вы ожидаете от результата. В этом случае я предлагаю вам вручную пройти (возможно, с помощью Excel или Calc) и сгенерировать имена и содержимое производных столбцов как минимум для нескольких строк. (Судя по всему, три верхних уровня можно отбросить, а два списка выглядят как кадры с идентичной структурой, которые можно уменьшить.)
Я не знаком с парсингом JSON. Я не включил конец фрейма данных, так как он очень длинный. Я хочу, чтобы столбцы были идентификатором (который является годом), другим идентификатором (номером идентификатора команды), точками ротации, значением, различием, рангом, отставанием и т. д.
Вы не включили data.frame
, это строка, но дело в том, что это не полная строка JSON. Ничего страшного, я надеюсь, что этого будет достаточно, если он будет прекращен (как указано выше). (Действительно, длинные данные на SO обычно не требуются, так что все в порядке.) Посмотрите на jsonlite
и rjson
.
Я подумал, что потребуется jsonlite, я просто не уверен, как их использовать для получения желаемого результата.
Это некрасиво. Я действительно хочу, чтобы кто-нибудь дал лучший ответ, тем более что он сохраняет вложенные кадры, что делает подмножество немного болезненным.
js <- jsonlite::fromJSON('{"body":{"overall_standings":{"years":[{"standings":null,"id":"2006"},{"standings":null,"id":"2007"},{"standings":null,"id":"2008"},{"standings":null,"id":"2009"},{"standings":null,"id":"2010"},{"standings":null,"id":"2011"},{"standings":{"teams":[{"Pitching":{"roto_points":"47.0","categories":[{"abbr":"S","roto_points":"91","value":"New York Yankees","diff":"9","rank":5},{"roto_points":"90","value":"New York Yankees","abbr":"W","diff":"7","rank":7},{"roto_points":"1383","value":"New York Yankees","abbr":"K","diff":"10","rank":4},{"abbr":"WHIP","roto_points":"1.2451","value":"New York Yankees","diff":"10","rank":4},{"abbr":"ERA","roto_points":"3.685","value":"New York Yankees","diff":"11","rank":3}]},"Total":{"behind":"0.0","roto_points":"98.0","diff":"-4.0","rank":1},"order":1,"name":"New York Yankees","Batting":{"roto_points":"51.0","categories":[{"abbr":"OBP","roto_points":"0.3371","value":"New York Yankees","diff":"7","rank":7},{"roto_points":"905","value":"New York Yankees","abbr":"RBI","diff":"10","rank":4},{"roto_points":"955","value":"New York Yankees","abbr":"R","diff":"12","rank":2},{"abbr":"SB","roto_points":"183","value":"New York Yankees","diff":"13","rank":1},{"abbr":"HR","roto_points":"247","value":"New York Yankees","diff":"9","rank":5}]},"id":"2"},{"Pitching":{"roto_points":"44.5","categories":[{"abbr":"S","roto_points":"105","value":"Los Angeles Dodgers","diff":"12","rank":2},{"roto_points":"96","value":"Los Angeles Dodgers","abbr":"W","diff":"10.5","rank":3},{"roto_points":"1410","value":"Los Angeles Dodgers","abbr":"K","diff":"11","rank":3},{"abbr":"WHIP","roto_points":"1.2798","value":"Los Angeles Dodgers","diff":"3","rank":11},{"abbr":"ERA","roto_points":"3.810","value":"Los Angeles Dodgers","diff":"8","rank":6}]},"Total":{"behind":"4.0","roto_points":"94.0","diff":"0.0","rank":2},"order":2,"name":"Los Angeles Dodgers","Batting":{"roto_points":"49.5","categories":[{"abbr":"OBP","roto_points":"0.3446","value":"Los Angeles Dodgers","diff":"11","rank":3},{"roto_points":"907","value":"Los Angeles Dodgers","abbr":"RBI","diff":"11","rank":3},{"roto_points":"909","value":"Los Angeles Dodgers","abbr":"R","diff":"9","rank":5},{"abbr":"SB","roto_points":"152","value":"Los Angeles Dodgers","diff":"11","rank":3},{"abbr":"HR","roto_points":"234","value":"Los Angeles Dodgers","diff":"7.5","rank":6}]},"id":"1"}]},"id":"2012"}]}}}')
Он начинается со списка внутри списка внутри списка, поэтому давайте избавимся от ненужных слоев. (Я показываю промежуточный код, который является просто демонстрационным, без вывода, поскольку он довольно многословен ... думаю, что я вас провожу.)
str(js[[1]])
str(js[[1]][[1]])
str(js[[1]][[1]][[1]])
dat <- js[[1]][[1]][[1]]
На последнем str
вы можете заметить, что у dat$standings$teams
довольно много NULL
, давайте их отфильтруем:
dat <- Filter(length, dat$standings$teams)[[1]]
Хорошо, быстрая вспомогательная функция и вывод:
library(dplyr)
addnames <- function(x, nm, sep = "_") setNames(x, paste0(nm, sep, colnames(x)))
dat2 <- tbl_df(bind_cols(
dat[c("id","name","order")],
addnames(dat$Total, "Total"),
addnames(dat$Pitching["roto_points"], "Pitching"),
addnames(dat$Batting["roto_points"], "Batting")
)) %>%
mutate(
Pitching_categories = dat$Pitching$categories,
Batting_categories = dat$Batting$categories
)
dat2
# # A tibble: 2 x 11
# id name order Total_behind Total_roto_points Total_diff Total_rank Pitching_roto_points Batting_roto_points Pitching_categories Batting_categories
# <chr> <chr> <int> <chr> <chr> <chr> <int> <chr> <chr> <list> <list>
# 1 2 New York Yankees 1 0.0 98.0 -4.0 1 47.0 51.0 <data.frame [5 x 5]> <data.frame [5 x 5]>
# 2 1 Los Angeles Dodgers 2 4.0 94.0 0.0 2 44.5 49.5 <data.frame [5 x 5]> <data.frame [5 x 5]>
У него есть два вложенных фрейма, так что вы будете немного изобретательны при работе с ними. Я предполагаю, что это не лучший способ взглянуть на это, но это начало. Конечно, можно (с еще большим количеством смазки для локтей) расширить эти две строки (по одной на команду) до десяти строк (по пять на команду, что соответствует пяти строкам, вложенным в каждый из Pitching
и Batting
), но это может быть не то, что вы необходимость.
unnest(dat2)
# # A tibble: 10 x 19
# id name order Total_behind Total_roto_points Total_diff Total_rank Pitching_roto_poi~ Batting_roto_po~ abbr roto_points value diff rank abbr1 roto_points1 value1 diff1 rank1
# <chr> <chr> <int> <chr> <chr> <chr> <int> <chr> <chr> <chr> <chr> <chr> <chr> <int> <chr> <chr> <chr> <chr> <int>
# 1 2 New York ~ 1 0.0 98.0 -4.0 1 47.0 51.0 S 91 New York~ 9 5 OBP 0.3371 New York~ 7 7
# 2 2 New York ~ 1 0.0 98.0 -4.0 1 47.0 51.0 W 90 New York~ 7 7 RBI 905 New York~ 10 4
# 3 2 New York ~ 1 0.0 98.0 -4.0 1 47.0 51.0 K 1383 New York~ 10 4 R 955 New York~ 12 2
# 4 2 New York ~ 1 0.0 98.0 -4.0 1 47.0 51.0 WHIP 1.2451 New York~ 10 4 SB 183 New York~ 13 1
# 5 2 New York ~ 1 0.0 98.0 -4.0 1 47.0 51.0 ERA 3.685 New York~ 11 3 HR 247 New York~ 9 5
# 6 1 Los Angel~ 2 4.0 94.0 0.0 2 44.5 49.5 S 105 Los Ange~ 12 2 OBP 0.3446 Los Ange~ 11 3
# 7 1 Los Angel~ 2 4.0 94.0 0.0 2 44.5 49.5 W 96 Los Ange~ 10.5 3 RBI 907 Los Ange~ 11 3
# 8 1 Los Angel~ 2 4.0 94.0 0.0 2 44.5 49.5 K 1410 Los Ange~ 11 3 R 909 Los Ange~ 9 5
# 9 1 Los Angel~ 2 4.0 94.0 0.0 2 44.5 49.5 WHIP 1.2798 Los Ange~ 3 11 SB 152 Los Ange~ 11 3
# 10 1 Los Angel~ 2 4.0 94.0 0.0 2 44.5 49.5 ERA 3.810 Los Ange~ 8 6 HR 234 Los Ange~ 7.5 6
Как я уже сказал, это не кажется красивым или даже элегантным, но, возможно, это хорошее начало для вас, или, может быть, кто-то другой может воспользоваться этим для лучшего решения.
Спасибо! Он дает мне именно то, что мне нужно, во фрейме данных. Я, конечно, открыт для более элегантного решения, но просто счастлив получить решение!
Как включить год в столбец? После 2012 года есть дополнительные годы.
Jazzmatazz, полезно иметь строку json, которую можно анализировать, это неполно. Если вы удалите последнюю запятую из первой строки и добавите
]}}}
, он сделает ее достаточно полной, чтобы библиотеки json могли анализировать без жалоб.