我正在尝试使用Renjin从Java程序中存在的数据构建模型 . 我有一个 ArrayList
POJO对象列表,其中每个属性都是 String
, double
或 int
. 如果我调用 toString()
,记录看起来像这样:
Record{id='uibbd923e5929b43', countryCode='FR', revenue=3.14159, count=1}
Record{id='uicdd967e5942b55', countryCode='GB', revenue=0.07, count=49}
...
我实例化了R,在JVM中运行,如下所示:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("Renjin");
...并将 ArrayList
条记录放入R:
engine.put("records", records);
在R内部,记录存储为 <externalptr>
对象的列表 . 可以看到存储在指针内的值的字符串表示,例如,
engine.eval("print(data.frame(lapply(records, as.character), stringsAsFactors=FALSE))");
但是,我真的希望这些存储为具有正确数据类型的数据帧,而不是可以被视为字符串的外部指针列表 .
如何将 externalptr
的列表转换为数据帧?
更新:
这是我蹩脚的解决方法,至少现在是这样 . 将数据写入CSV:
CSVWriter writer = new CSVWriter(new FileWriter("tmp/output.csv"), '\t');
writer.writeNext(new String[] {"id", "countryCode", "revenue", "count"});
for (Record record : records){
writer.writeNext(new String[]{record.getId(),
record.getCountryCode(),
record.getRevenue().toString(),
record.getCount().toString()});
}
writer.close();
然后Renjin将CSV读入数据帧:
engine.eval("df <- read.table(\"tmp/output.csv\", header = TRUE)");
更新:
目前,我决定使用Rserve,因为它提供了更多的灵活性 . Rserve(vs Renjin)的一个缺点是我们现在需要确保R正在运行并安装了必要的软件包 .
1 回答
这可以作为一个小帮助库组合在一起,但是目前,您可以通过以下方式在Java中“手动”构建一个data.frame:
从上面可以看到,data.frame对象实际上只是一个列的列表,因此需要花费一点时间才能将一堆Java Bean(基本上是基于行的格式)添加到一组列中 .
添加“row.names”属性也很重要,该属性由nrow()等函数使用以获取data.frame对象的维度 .
上面的RowNamesVector是StringVector的一个专门实现,它根据需要计算row.names“1”,“2”,“3”等,而不为所有字符串分配内存 .