从R中的数据框中创建深层嵌套的JSON

时间:2016-07-07 19:37:39

标签: json r tidyr

我正在寻找一个漂亮整洁的数据框并使用R将其转换为深度嵌套的JSON。到目前为止,我还没有找到任何其他直接解决此任务的资源 - 大多数似乎都试图把它带到另一个方向(取消嵌套JSON)。

这是我开始使用的数据框的小型虚拟版本。想象一下,对公司内部的两个受众进行了调查,一个针对经理,另一个针对员工。调查有不同的问题,不同的ID,但许多问题重叠,我想比较两组之间的反应。最终目标是制作一个JSON,以匹配正确层次结构中两个调查的部分ID,问题ID和选项ID /文本。有些问题的子问题需要进一步的嵌套,这就是我遇到的困难。

library(dplyr)
library(tidyr)
library(jsonlite)

dummyDF <- data_frame(sectionId = c(rep(1,9),rep(2,3)),
                      questionId = c(rep(1,3),rep(2,6),rep(3,3)),
                      subquestionId = c(rep(NA,3),rep("2a",3),rep("2b",3),rep(NA,3)),
                      deptManagerQId = c(rep("m1",3),rep("m2",3),rep("m3",3),rep("m4",3)),
                      deptEmployeeQId = c(rep("e1",3),rep("e3",3),rep("e4",3),rep("e7",3)),
                      optionId = rep(c(1,2,3),4),
                      text = rep(c("yes","neutral","no"),4))

这是我想要达到的最终结果:

theGoal <- fromJSON('{
  "sections": [
    {
      "sectionId": "1",
      "questions": [
        {
          "questionId": "1",
          "deptManagerQId": "m1",
          "deptEmployeeQId": "e1",
          "options": [
            {
              "optionId": 1,
              "text": "yes"
            },
            {
              "optionId": 2,
              "text": "neutral"
            },
            {
              "optionId": 3,
              "text": "no"
            }
          ]
        },
        {
          "questionId": "2",
          "options": [
            {
              "optionId": 1,
              "text": "yes"
            },
            {
              "optionId": 2,
              "text": "neutral"
            },
            {
              "optionId": 3,
              "text": "no"
            }
          ],
          "subquestions": [
            {
              "subquestionId": "2a",
              "deptManagerQId": "m2",
              "deptEmployeeQId": "e3"
            },
            {
              "subquestionId": "2b",
              "deptManagerQId": "m3",
              "deptEmployeeQId": "e4"
            }
          ]
        },
        {
          "questionId": "3",
          "deptManagerQId": "m4",
          "deptEmployeeQId": "e7",
          "options": [
            {
              "optionId": 1,
              "text": "yes"
            },
            {
              "optionId": 2,
              "text": "neutral"
            },
            {
              "optionId": 3,
              "text": "no"
            }
          ]
        }
      ]
    }
  ]
}')

以下是我尝试使用来自tidyr的nest的几种方法,最终只是让我在那里的一部分或抛出错误信息。

1

list1 <- dummyDF %>% nest(-sectionId, .key=questions) %>% 
  mutate(questions = lapply(seq_along(.$questions), function(x) nest(.$questions[[x]], optionId, text, .key = options))) %>%
  list(sections = .)

2

nested1 <- dummyDF %>% nest(-sectionId, .key=questions) %>% 
  mutate(questions = lapply(seq_along(.$questions), function(x) nest(.$questions[[x]], optionId, text, .key = options)))

nested2 <- nested1 %>% mutate(questions = lapply(seq_along(.$questions), function(x) nest(.$questions[[x]], subquestionId, .key = subquestions))) 
#Gives this error: cannot group column options, of class 'list'

3

list2 <- dummyDF %>% nest(-sectionId, .key=questions) %>% 
  mutate(questions = lapply(seq_along(.$questions), 
                            function(x) {ifelse(is.na(.$questions[[x]]$subquestionId),
                                                function(x) {.$questions[[x]] %>% select(-subquestionId) %>% nest(optionId, text, .key = options)},
                                                function(x) {.$questions[[x]] %>% nest(subquestion_id, .key = subquestions)})})) %>% 
  list(sections = .) 
#Gives this error: attempt to replicate an object of type 'closure'

任何想法都将不胜感激。我对任何方法持开放态度。我把这个问题带到了当地的R用户小组聚会,但无法提出任何解决方案,所以我的手指越过这里。我意识到R可能不是实现这一目标的最佳工具,但它是我所知道的那个,所以我给它一个机会。感谢。

1 个答案:

答案 0 :(得分:0)

jsonlite::toJSON看起来是解决问题的好方法。

无缝地工作到列类型和列顺序(我更正说明对象是相同的)。如果您需要任何其他类型的JSON结构,我建议首先使用dplyrtidyr重构前端的data_frame。

library(jsonlite)
library(dplyr)

dummyDF <- data_frame(sectionId = c(rep(1,9),rep(2,3)),
                  questionId = c(rep(1,3),rep(2,6),rep(3,3)),
                  subquestionId = c(rep(NA,3),rep("2a",3),rep("2b",3),rep(NA,3)),
                  deptManagerQId = c(rep("m1",3),rep("m2",3),rep("m3",3),rep("m4",3)),
                  deptEmployeeQId = c(rep("e1",3),rep("e3",3),rep("e4",3),rep("e7",3)),
                  optionId = rep(c(1,2,3),4),
                  text = rep(c("yes","neutral","no"),4))

## Convert to a JSON object
json <- jsonlite::toJSON(dummyDF)


theGoal <- fromJSON(json) %>% tbl_df() %>% select_(.dots=names(dummyDF)) %>%
  ## Convert integer columns to numeric
  mutate_if(function(x) {if (typeof(x)=='integer') {TRUE} else {FALSE}},as.numeric)

## Compare the objects
all.equal(theGoal,dummyDF)
# TRUE

identical(theGoal,dummyDF)
# TRUE