кодирование выражения JSON из R с помощью jsonlite или чего-то еще

API, который я использую, требует, чтобы я отправил ему JSON сообщение, например:

y <- '[{"a":1, "b":"select", "c":["A", "B", "C"]}, 
       {"a":2, "b":"text"},
       {"a":3, "b":"select", "c":["D", "E", "F", "G"]}]'

Обратите внимание, что в случае "b" : "select" есть еще одна переменная c со значением, являющимся массивом.

Когда я пытаюсь запустить fromJSON(y) (в пакете jsonlite), я получаю data.frame, где 3-й столбец представляет собой список:

> z <- fromJSON(y) 
> class(z)
[1] "data.frame"
> z %>% glimpse()
Observations: 3
Variables: 3
$ a (int) 1, 2, 3
$ b (chr) "select", "text", "select"
$ c (list) A, B, C, NULL, D, E, F, G

Но когда я конвертирую его обратно в JSON (это формат, который я хочу отправить в API), переменная c появляется там, где ее быть не должно.

[{"a":1,"b":"select","c":["A","B","C"]},
 {"a":2,"b":"text","c":{}},
 {"a":3,"b":"select","c":["D","E","F","G"]}]

Есть ли другая структура данных R, которая могла бы надежно вывести меня из фрейма данных в исходное сообщение JSON, используя jsonlite (или что-то еще)? Как это будет работать?


person wdkrnls    schedule 14.01.2016    source источник
comment
Я думаю, что если вы используете RJSONIO:fromJSON, а затем jsonlite::toJSON, вы получите то, что хотите.   -  person Martin Schmelzer    schedule 14.01.2016


Ответы (2)


с jsonlite вы можете сделать следующее:

z <- fromJSON(y, simplifyDataFrame = F)
toJSON(z, auto_unbox=T)

Кроме того, рассмотрим следующий случай, когда последним элементом c является ["D"]:

y2 <- '[{"a":1, "b":"select", "c":["A", "B", "C"]}, 
        {"a":2, "b":"text"}, 
        {"a":3, "b":"select", "c":["D"]}]'

z2 <- fromJSON(y2, simplifyDataFrame = F)
toJSON(z2, auto_unbox=T)

Результат таков:

[{"a":1,"b":"select","c":["A","B","C"]},
 {"a":2,"b":"text"},
 {"a":3,"b":"select","c":"D"}]

Это может быть проблемой, потому что последний элемент c равен "D", а не ["D"].

Чтобы предотвратить это, не используйте auto_unbox. Используйте unbox осторожно следующим образом:

z2 <- fromJSON(y2, simplifyDataFrame = F)
for(i in 1:length(z2)){
  z2[[i]][[1]] <- unbox(z2[[i]][[1]])
  z2[[i]][[2]] <- unbox(z2[[i]][[2]])
}
toJSON(z2)
person skwon    schedule 14.01.2016
comment
О, это тоже ново для меня! Кое-что узнал :D - person Martin Schmelzer; 14.01.2016
comment
Это отличный совет - я долго боролся с этой проблемой. - person Iain; 07.07.2016

Если вам нужен фрейм данных для вычислений, вы можете это сделать (функция rmNullObs взята из здесь):

z <- fromJSON(y)

is.NullOb <- function(x) is.null(x) | all(sapply(x, is.null))

## Recursively step down into list, removing all such objects 
rmNullObs <- function(x) {
  x <- Filter(Negate(is.NullOb), x)
  lapply(x, function(x) if (is.list(x)) rmNullObs(x) else x)
}    

z_list <- rmNullObs(as.list(as.data.frame(t(z))))
toJSON(unname(z_list), auto_unbox=T)

Это преобразует фрейм данных в список, удаляет NULL и преобразует обратно в JSON.

Если вам не нужен фреймворк данных, см. ответ @skwon

person NicE    schedule 14.01.2016
comment
Это похоже на то, что я ищу, но я получаю: {"1":{"a":1,"b":"select","c":["A","B","C"]},"2":{"a":2,"b":"text"},"3":{"a":3,"b":"select","c":["D","E","F","G"]}} из вашего кода. Мне нужно, чтобы внешняя структура данных была массивом. - person wdkrnls; 14.01.2016
comment
забыл unname список, исправил. - person NicE; 14.01.2016