我试图从数据框中获取JSON数组对象,其中每个JSON对象都是数据框的子集
> x <- 1:5
> y <-c('a','b','c','d','e')
> z <-c(1,1,1,2,2)
> df <-data.frame(x,y,z)
> df
x y z
1 1 a 1
2 2 b 1
3 3 c 1
4 4 d 2
5 5 e 2
> rjson::toJSON(df)
[1] "{\"x\":[1,2,3,4,5],\"y\":[\"a\",\"b\",\"c\",\"d\",\"e\"],\"z\":[1,1,1,2,2]}"
> df1 = toJSONArray2(na.omit(df), json = F, names = F)
> rjson::toJSON(df1)
[1] "[[1,\"a\",1],[2,\"b\",1],[3,\"c\",1],[4,\"d\",2],[5,\"e\",2]]"
我需要的输出是
[[[1,a],[2,b],[3,c]],[[4,d],[5,e]]]
在方法I之下,我能够按预期获得数据帧列表,但无法获得所需的json输出。
> x <- foreach(i=1:2) %do% { subset(df,df$z==i)[c(1,2)]}
> x
[[1]]
x y
1 1 a
2 2 b
3 3 c
[[2]]
x y
4 4 d
5 5 e
找到解决方案。
> x <- foreach(i=1:2) %do% {
tmp <-subset(df,df$z==i)[c(1,2)]
toJSONArray2(na.omit(tmp), json = F, names = F)
}
> rjson::toJSON(x)
我需要一个没有toJSONArray2的实现,这很慢
答案 0 :(得分:5)
toJSONArray2
中的rCharts
功能很慢,主要是因为使用了RJSONIO
。我正在使用rjson
将其更新为更快的实现。这是我到目前为止所拥有的。我从orient
借用了pandas
参数的想法。
to_json = function(df, orient = "columns", json = T){
dl = as.list(df)
dl = switch(orient,
columns = dl,
records = do.call('zip_vectors_', dl),
values = do.call('zip_vectors_', setNames(dl, NULL))
)
if (json){
dl = rjson::toJSON(dl)
}
return(dl)
}
zip_vectors_ = function(..., names = F){
x = list(...)
y = lapply(seq_along(x[[1]]), function(i) lapply(x, pluck_(i)))
if (names) names(y) = seq_along(y)
return(y)
}
pluck_ = function (element){
function(x) x[[element]]
}
以下示例将向您显示to_json
比toJSONArray2
快20倍,其中大部分是由于使用rjson
而不是RJSONIO
而来的。
N = 10^3
df <- data.frame(
x = rpois(N, 10),
y = sample(LETTERS, N, replace = T),
z = rpois(N, 5)
)
library(microbenchmark)
autoplot(microbenchmark(
to_json(df, orient = "values", json = T),
toJSONArray2(df, names = F),
times = 5
))
更新:在仔细阅读您的问题后,我意识到我们可以使用dplyr
和to_json
library(dplyr)
dfl = df %.%
group_by(z) %.%
do(function(x){
to_json(x[-3], orient = 'values', json = F)
})
答案 1 :(得分:2)
对于试图回答的其他人,toJSONArray[2]
函数位于rCharts
包中。您的解决方案非常紧凑,但可以通过sapply
和split
解除一些问题并收紧:
library(rjson)
library(rCharts)
x <- 1:5
y <- c('a', 'b' ,'c' ,'d' ,'e')
z <- c(1, 1, 1, 2, 2)
df <- data.frame(x, y, z)
toJSON(df)
out <- toJSONArray(sapply(split(df[,1:2], df$z), function(x) {
toJSONArray2(x, names=FALSE, json = FALSE)
}))
# doing gsub only for SO example output
cat(gsub("\\n", "", out))
## [ [ [ 1,"a" ],[ 2,"b" ],[ 3,"c" ] ],[ [ 4,"d" ],[ 5,"e" ] ] ]
根据请求者,我们来看看toJSONArray[2]()
中的rCharts
函数实现:
toJSONArray <- function(obj, json = TRUE, nonames = TRUE){
list2keyval <- function(l){
keys = names(l)
lapply(keys, function(key){
list(key = key, values = l[[key]])
})
}
obj2list <- function(df){
l = plyr::alply(df, 1, as.list)
if(nonames){ names(l) = NULL }
return(l)
}
if (json){
toJSON(obj2list(obj))
} else {
obj2list(obj)
}
}
toJSONArray2 <- function(obj, json = TRUE, names = TRUE, ...){
value = lapply(1:nrow(obj), function(i) {
res <- as.list(obj[i, ])
if (!names) names(res) <- NULL # remove names (e.g. {x = 1, y = 2} => {1, 2})
return(res)
})
if (json){
return(toJSON(value, .withNames = F, ...))
} else {
names(value) <- NULL;
return(value)
}
}
这些函数已经过优化,但toJSONArray2
基本上使用apply
函数之一作为for
循环,所以让我们看看JSON的自编码是否符合您的需求好点。以下可能对您来说更快,但您需要为生产代码稍微调整一下(如果您需要取消引用的整数):
out <- sapply(split(df[,1:2], df$z), function(x) {
out.2 <- apply(x, 1, function(y) {
return(paste0(toJSON(unlist(as.list(y)), .withNames = FALSE), sep=",", collapse=""))
})
out.2 <- paste(out.2, sep=", ", collapse=" ")
out.2 <- gsub(",$", "", out.2)
return(sprintf("[ %s ], ", out.2))
})
cat(sprintf("[ %s ]", gsub(", $", "", paste(unlist(out), collapse=""))))
## [ [ [ "1", "a" ], [ "2", "b" ], [ "3", "c" ] ], [ [ "4", "d" ], [ "5", "e" ] ] ]
它与rCharts
实现共享一些类似的模式,但完全专注于将因子分割数据帧的行打成您需要的格式。