![](/img/trans.png)
[英]Unable to convert JSON array containing nested objects to POJO arraylist
[英]Convert ArrayList of POJO objects to R dataframe with Renjin
我正在尝试使用Renjin从Java程序中存在的数据构建模型。 我有一个POJO对象的ArrayList
列表,其中每个属性是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
的列表转换为数据框?
至少到目前为止,这是我la脚的解决方法。 将数据写入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(与Renjin相比)的一个缺点是我们现在需要确保R正在运行并已安装了必要的软件包。
将其作为一个小的帮助程序库可能会很有用,但是目前,您可以按照以下方式在Java中逐步“手动”构造data.frame:
StringArrayVector.Builder id = new StringArrayVector.Builder();
StringArrayVector.Builder country = new StringArrayVector.Builder();
DoubleArrayVector.Builder revenue = new DoubleArrayVector.Builder();
for(Record record : records) {
id.add(record.getId());
country.add(record.getCountry());
revenue.add(record.getRevenue());
}
ListVector.NamedBuilder myDf = new ListVector.NamedBuilder();
myDf.setAttribute(Symbols.CLASS, StringVector.valueOf("data.frame"));
myDf.setAttribute(Symbols.ROW_NAMES, new RowNamesVector(records.size());
myDf.add("id", id.build());
myDf.add("country", country.build());
myDf.add("revenue", revenue.build());
从上面可以看到,一个data.frame对象实际上只是一个列列表,因此要花点时间才能使Java Beans的集合(本质上是基于行的格式)成为列的集合。
添加“ row.names”属性也很重要,nrow()之类的函数使用该属性来获取data.frame对象的尺寸。
上面的RowNamesVector是StringVector的一种特殊实现,可以按需计算row.names“ 1”,“ 2”,“ 3”等,而无需为所有字符串分配内存。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.