Преобразовать JSON в data.frame с более чем 2 столбцами

#json #r #dataframe #sapply #do.call

#json #r #фрейм данных #sapply #do.call

Вопрос:

Я пытаюсь правильно преобразовать JSON в data.frame с 3 столбцами.

Это упрощение моих данных

 # simplification of my real data
my_data <- '{"Bag 1": [["bananas", 1], ["oranges", 2]],"Bag 2": [["bananas", 3], ["oranges", 4], ["apples", 5]]}'

library(jsonlite)

my_data <- fromJSON(my_data)

> my_data
$`Bag 1`
     [,1]      [,2]
[1,] "bananas" "1" 
[2,] "oranges" "2" 

$`Bag 2`
     [,1]      [,2]
[1,] "bananas" "3" 
[2,] "oranges" "4" 
[3,] "apples"  "5" 
  

Я пытаюсь преобразовать это в data.frame

 # this return an error about "arguments imply differing number of rows: 2, 3"
my_data <- as.data.frame(my_data)

> my_data <- as.data.frame(my_data)
Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE,  : 
  arguments imply differing number of rows: 2, 3
  

Это мое решение для создания data.frame

 # my solution 
my_data <- data.frame(fruit = do.call(c, my_data),
  bag_number = rep(1:length(my_data), 
  sapply(my_data, length)))

# how it looks
my_data

> my_data
         fruit bag_number
Bag 11 bananas          1
Bag 12 oranges          1
Bag 13       1          1
Bag 14       2          1
Bag 21 bananas          2
Bag 22 oranges          2
Bag 23  apples          2
Bag 24       3          2
Bag 25       4          2
Bag 26       5          2
  

Но моя идея состоит в том, чтобы получить что-то подобное, чтобы избежать проблем, подобных my_data[a:b,1] тому, когда я хочу использовать ggplot2 и другие.

 fruit   | quantity | bag_number
oranges | 2        | 1
bananas | 1        | 1
oranges | 4        | 2
bananas | 3        | 2
apples  | 5        | 2
  

Комментарии:

1. Ваш примерный набор данных не выдает первоначальный вывод. Вместо этого он создает вложенный список списков, с которым очень сложно работать. Я использую rjson::fromJSON .

2. спасибо, да, я изменил его сейчас

Ответ №1:

 library(plyr)

# import data (note that the rJSON package does this differently than the jsonlite package)
data.import <- jsonlite::fromJSON(my_data)

# combine all data using plyr
df <- ldply(data.import, rbind)

# clean up column names
colnames(df) <- c('bag_number', 'fruit', 'quantity')

  bag_number   fruit quantity
1      Bag 1 bananas        1
2      Bag 1 oranges        2
3      Bag 2 bananas        3
4      Bag 2 oranges        4
5      Bag 2  apples        5
  

Комментарии:

1. Я понимаю, что jsonlite и rJSON делают то же самое, но на самом деле разные. Большое спасибо.

Ответ №2:

purrr / tidyverse версия. Вы также получаете правильные типы с этим и избавляетесь от « Bag «:

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

fromJSON(my_data, flatten=TRUE) %>% 
  map_df(~as.data.frame(., stringsAsFactors=FALSE), .id="bag") %>%
  type_convert() %>% 
  setNames(c("bag_number", "fruit", "quantity")) -> df

df$bag_number <- gsub("Bag ", "", df$bag_number)
  

Комментарии:

1. Большое спасибо. purrr также полезно.