从R格式化JSON输出的策略

uhry853o  于 2023-05-08  发布在  其他
关注(0)|答案(5)|浏览(221)

我试图找出从R生成JSON文件的最佳方法。我在R中有以下 Dataframe tmp

> tmp
  gender age welcoming proud tidy unique
1      1  30         4     4    4      4
2      2  34         4     2    4      4
3      1  34         5     3    4      5
4      2  33         2     3    2      4
5      2  28         4     3    4      4
6      2  26         3     2    4      3
tmp <- data.frame(
  gender = c(1L, 2L, 1L, 2L, 2L, 2L),
  age = c(30, 34, 34, 33, 28, 26),
  welcoming = c(4L, 4L, 5L, 2L, 4L, 3L),
  proud = c(4L, 2L, 3L, 3L, 3L, 2L),
  tidy = c(4L, 4L, 4L, 2L, 4L, 4L),
  unique = c(4L, 4L, 5L, 4L, 4L, 3L)
)

使用rjson包,运行toJSON(tmp)行,生成以下JSON文件:

{"gender":[1,2,1,2,2,2],
 "age":[30,34,34,33,28,26],
 "welcoming":[4,4,5,2,4,3],
 "proud":[4,2,3,3,3,2],
  "tidy":[4,4,4,2,4,4],
  "unique":[4,4,5,4,4,3]}

我还试验了RJSONIO包; toJSON()的输出是相同的。我想生成的是以下结构:

{"traits":["gender","age","welcoming","proud", "tidy", "unique"],
   "values":[   
            {"gender":1,"age":30,"welcoming":4,"proud":4,"tidy":4, "unique":4},
            {"gender":2,"age":34,"welcoming":4,"proud":2,"tidy":4, "unique":4},
            ....
            ]

我不知道该怎么做。我意识到我可以使用python逐行解析它,但我觉得可能有更好的方法来做到这一点。我还意识到,R中的数据结构没有反映JSON文件(特别是traits行)中所需的元信息,但我主要感兴趣的是生成格式类似行的数据

{"gender":1,"age":30,"welcoming":4,"proud":4,"tidy":4, "unique":4}

我可以手动添加第一行。
编辑:我发现了一个有用的blog帖子,作者处理了一个类似的问题,并提供了一个解决方案。此函数从 Dataframe 生成格式化的JSON文件。

toJSONarray <- function(dtf){
clnms <- colnames(dtf)

name.value <- function(i){
quote <- '';
# if(class(dtf[, i])!='numeric'){
if(class(dtf[, i])!='numeric' && class(dtf[, i])!= 'integer'){ # I modified this line so integers are also not enclosed in quotes
quote <- '"';
}

paste('"', i, '" : ', quote, dtf[,i], quote, sep='')
}

objs <- apply(sapply(clnms, name.value), 1, function(x){paste(x, collapse=', ')})
objs <- paste('{', objs, '}')

# res <- paste('[', paste(objs, collapse=', '), ']')
res <- paste('[', paste(objs, collapse=',\n'), ']') # added newline for formatting output

return(res)
}
bq3bfh9z

bq3bfh9z1#

使用jsonlite包:

> jsonlite::toJSON(list(traits = names(tmp), values = tmp), pretty = TRUE)
{
  "traits": ["gender", "age", "welcoming", "proud", "tidy", "unique"],
  "values": [
    {
      "gender": 1,
      "age": 30,
      "welcoming": 4,
      "proud": 4,
      "tidy": 4,
      "unique": 4
    },
    {
      "gender": 2,
      "age": 34,
      "welcoming": 4,
      "proud": 2,
      "tidy": 4,
      "unique": 4
    },
    {
      "gender": 1,
      "age": 34,
      "welcoming": 5,
      "proud": 3,
      "tidy": 4,
      "unique": 5
    },
    {
      "gender": 2,
      "age": 33,
      "welcoming": 2,
      "proud": 3,
      "tidy": 2,
      "unique": 4
    },
    {
      "gender": 2,
      "age": 28,
      "welcoming": 4,
      "proud": 3,
      "tidy": 4,
      "unique": 4
    },
    {
      "gender": 2,
      "age": 26,
      "welcoming": 3,
      "proud": 2,
      "tidy": 4,
      "unique": 3
    }
  ]
}
5kgi1eie

5kgi1eie2#

在Andrie的apply思想的基础上,您可以在调用toJSON之前通过修改tmp变量来获得所需的内容。

library(RJSONIO)
modified <- list(
  traits = colnames(tmp),
  values = unname(apply(tmp, 1, function(x) as.data.frame(t(x))))
)
cat(toJSON(modified))
vm0i2vca

vm0i2vca3#

在Andrie和Richie的思想的基础上,使用alply而不是apply来避免将数字转换为字符:

library(RJSONIO)
library(plyr)
modified <- list(
  traits = colnames(tmp),
  values = unname(alply(tmp, 1, identity))
)
cat(toJSON(modified))

plyr的alply类似于apply,但会自动返回一个列表;而如果没有Richie Cotton的答案中更复杂的函数,apply将返回一个向量或数组。这些额外的步骤,包括t,意味着如果你的数据集有任何非数字列,数字将被转换为字符串。所以使用alply避免了这种担心。
例如,使用tmp数据集并添加

tmp$grade <- c("A","B","C","D","E","F")

然后将此代码(使用alply)与另一个示例(使用apply)进行比较。

dw1jzc5e

dw1jzc5e4#

在我看来,您可以通过将data.frame的每一行发送到JSON中,并使用相应的apply语句来实现这一点。
对于单行:

library(RJSONIO)

> x <- toJSON(tmp[1, ])
> cat(x)
{
 "gender": 1,
"age":     30,
"welcoming": 4,
"proud": 4,
"tidy": 4,
"unique": 4 
}

整个data.frame

x <- apply(tmp, 1, toJSON)
cat(x)
{
 "gender": 1,
"age":     30,
"welcoming": 4,
"proud": 4,
"tidy": 4,
"unique": 4 
} {

...

} {
 "gender": 2,
"age":     26,
"welcoming": 3,
"proud": 2,
"tidy": 4,
"unique": 3 
}
4ngedf3f

4ngedf3f5#

另一种选择是使用split将具有N行的data.frame拆分为具有1行的N个data.frames。

library(RJSONIO)
modified <- list(
   traits = colnames(tmp),
   values = split(tmp, seq_len(nrow(tmp)))
)
cat(toJSON(modified))

相关问题