是否有一种干净的方法可以将data.frames上的默认“/ json”后缀选项更改为基于列而不是基于行?
如果我理解正确,R中的Data.frames实际上只是命名列表,其中每个列表的长度与其他列表的长度相同。使用jsonlite
,可以很容易地显示差异(简单示例,是):
library(jsonlite)
ll <- list(xx=1:3, yy=6:8)
dd <- data.frame(xx=1:3, yy=6:8)
toJSON(dd)
# [1] "[ { \"xx\" : 1, \"yy\" : 6 }, { \"xx\" : 2, \"yy\" : 7 }, { \"xx\" : 3, \"yy\" : 8 } ]"
toJSON(ll)
# [1] "{ \"xx\" : [ 1, 2, 3 ], \"yy\" : [ 6, 7, 8 ] }"
toJSON(dd, dataframe='column')
# [1] "{ \"xx\" : [ 1, 2, 3 ], \"yy\" : [ 6, 7, 8 ] }"
toJSON(as.list(dd))
# [1] "{ \"xx\" : [ 1, 2, 3 ], \"yy\" : [ 6, 7, 8 ] }"
最后三个是相同的。通过将dataframe
参数用于toJSON
或将data.frame
强制转换为list
,可以很容易地强制它看起来相同。
使用OpenCPU的API,调用看起来很相似:
$ curl http://localhost:7177/ocpu/library/base/R/list/json -H "Content-Type: application/json" -d '{ "xx":[1,2,3], "yy":[6,7,8] }'
{
"xx" : [
1,
2,
3
],
"yy" : [
6,
7,
8
]
}
$ curl http://localhost:7177/ocpu/library/base/R/data.frame/json -H "Content-Type: application/json" -d '{ "xx":[1,2,3], "yy":[6,7,8] }'
[
{
"xx" : 1,
"yy" : 6
},
{
"xx" : 2,
"yy" : 7
},
{
"xx" : 3,
"yy" : 8
}
]
如果我希望data.frame
本身是基于JSON的列,那么我需要将其强制转换为list
:
$ curl http://localhost:7177/ocpu/library/base/R/data.frame -H "Content-Type: application/json" -d '{ "xx":[1,2,3], "yy":[6,7,8] }'
/ocpu/tmp/x000a0fb8/R/.val
/ocpu/tmp/x000a0fb8/stdout
/ocpu/tmp/x000a0fb8/source
/ocpu/tmp/x000a0fb8/console
/ocpu/tmp/x000a0fb8/info
$ curl http://localhost:7177/ocpu/library/base/R/as.list/json -d "x=x000a0fb8"
{
"xx" : [
1,
2,
3
],
"yy" : [
6,
7,
8
]
}
三个问题:
有没有办法将OpenCPU auto-JSON -ification的默认行为更改为基于列?
是否有理由(除了“必须默认某事”)它默认为基于行? (这样我就能更好地理解基础和效率,而不是挑战。)
但这是学术性的,因为大多数(如果不是全部)接受JSON输出的库都会透明地理解和转换格式。右
(Win7 x64,R 3.0.3,opencpu 1.2.3,jsonlite 0.9.4)
(PS:谢谢,Jeroen,OpenCPU非常棒!我玩的越多,我就越喜欢。)
答案 0 :(得分:3)
对于dataframe
个对象,您可以使用HTTP GET
并设置dataframe
参数:
GET http://localhost:7177/ocpu/tmp/x000a0fb8/json?dataframe=rows
例如,Boston
包中的MASS
对象也是一个数据框:
https://cran.ocpu.io/MASS/data/Boston/json?dataframe=columns
https://cran.ocpu.io/MASS/data/Boston/json?dataframe=rows
对于HTTP GET
端点的.../json
个请求,所有http参数都映射到jsonlite package toJSON
函数中的参数。您还可以指定其他toJSON
参数:
https://cran.ocpu.io/MASS/data/Boston/json?dataframe=columns&digits=4
要查看哪些参数可用,请查看jsonlite manual或this post。
请注意,这只适用于您执行两步操作的步骤:首先在返回HTTP POST
的函数上dataframe
,然后使用{json
格式检索该对象{1}}请求。当您执行使用HTTP GET
修复toJSON
请求的一步快捷方式时,无法指定POST
参数,因为在/json
请求中,HTTP参数始终映射到函数调用。
此默认设置的原因是基于行的设计似乎是编码表格数据的最常规和可互操作的方式。 jsonlite paper/vignette详细介绍了一些问题。请注意,它也可以反过来:您不必调用POST
函数来创建数据框,只需在表单中发布参数:
data.frame
会自动将其转换为数据框:
[{"xx":1,"yy":6},{"xx":2,"yy":7},{"xx":3,"yy":8}]
答案 1 :(得分:0)
如果您想避免GET请求,可以使用Javascript进行转换:
#include <stdio.h>
int main(void) {
int max = 1000;
for (int i = 0; i < max; ++i) {
printf("%d", i);
if (i % 4 == 3)
putchar('\n');
}
return 0;
}
结果:
var df = [
{"id":1,"Sepal.Length":5.1,"Sepal.Width":3.5,"Petal.Length":1.4,"Petal.Width":0.2,"Species":"setosa"},
{"id":2,"Sepal.Length":4.9,"Sepal.Width":3,"Petal.Length":1.4,"Petal.Width":0.2,"Species":"setosa"},
{"id":3,"Sepal.Length":4.7,"Sepal.Width":3.2,"Petal.Length":1.3,"Petal.Width":0.2,"Species":"setosa"}
]
var columns = Object.keys(df[0]);
var dfcolumns = {};
for (i = 0; i < columns.length; i++) {
var column = [];
var colname = columns[i];
for (j = 0; j < df.length; j++) {
column.push(df[j][colname]);
}
dfcolumns[colname] = column;
}
console.log(dfcolumns);