Преобразование вложенного JSON в фрейм данных в R

У меня есть довольно длинный список 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 

Заранее спасибо!

Jazzmatazz, полезно иметь строку json, которую можно анализировать, это неполно. Если вы удалите последнюю запятую из первой строки и добавите ]}}}, он сделает ее достаточно полной, чтобы библиотеки json могли анализировать без жалоб.

r2evans 27.10.2018 16:33

Было бы действительно полезно узнать, что вы пробовали до сих пор и чего вы ожидаете от результата. В этом случае я предлагаю вам вручную пройти (возможно, с помощью Excel или Calc) и сгенерировать имена и содержимое производных столбцов как минимум для нескольких строк. (Судя по всему, три верхних уровня можно отбросить, а два списка выглядят как кадры с идентичной структурой, которые можно уменьшить.)

r2evans 27.10.2018 16:38

Я не знаком с парсингом JSON. Я не включил конец фрейма данных, так как он очень длинный. Я хочу, чтобы столбцы были идентификатором (который является годом), другим идентификатором (номером идентификатора команды), точками ротации, значением, различием, рангом, отставанием и т. д.

Jazzmatazz 27.10.2018 17:12

Вы не включили data.frame, это строка, но дело в том, что это не полная строка JSON. Ничего страшного, я надеюсь, что этого будет достаточно, если он будет прекращен (как указано выше). (Действительно, длинные данные на SO обычно не требуются, так что все в порядке.) Посмотрите на jsonlite и rjson.

r2evans 27.10.2018 17:15

Я подумал, что потребуется jsonlite, я просто не уверен, как их использовать для получения желаемого результата.

Jazzmatazz 27.10.2018 22:09
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
663
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это некрасиво. Я действительно хочу, чтобы кто-нибудь дал лучший ответ, тем более что он сохраняет вложенные кадры, что делает подмножество немного болезненным.

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

Как я уже сказал, это не кажется красивым или даже элегантным, но, возможно, это хорошее начало для вас, или, может быть, кто-то другой может воспользоваться этим для лучшего решения.

Спасибо! Он дает мне именно то, что мне нужно, во фрейме данных. Я, конечно, открыт для более элегантного решения, но просто счастлив получить решение!

Jazzmatazz 28.10.2018 17:53

Как включить год в столбец? После 2012 года есть дополнительные годы.

Jazzmatazz 29.10.2018 15:10

Другие вопросы по теме