使用 Rserve 实现 R 程序的复杂数据返回
2017-09-22 16:10
597 查看
在 RCaller 无法返回复杂数据的研究 我们知道 RCaller 无法处理复杂数据的返回,那么就看看其他工具吧,比如 Rserve。
使用下来的感觉是 Rserve 虽然能把值都给你,但是怎么获取却是一个艰难的过程,比如和 RCaller 一样,对矩阵值的读取也是先列后行,定位到具体的值的变量上,API 显然没有与时俱进,不用泛型,使用古老的 Vector 类型,经常要强制转型,要不是 debug, 我怎么知道那个列是什么数据类型啊。
private RList exeRMatchCode(PropensityMatchInput input, Map<String, List<String>> varResultMap,
List<String> covairateNames) {
logger.info("entering exeRMatchCode()");
try {
RConnection rc = new RConnection();
for (String key : varResultMap.keySet()){
logger.info("key is :: {}", key);
List<String> varVals = varResultMap.get(key);
String[] valStrs = new String[varVals.size()];
int num = 0;
for (String s : varVals){
valStrs[num++] = s;
}
rc.assign(key, valStrs);
}
logger.info("各个变量值的数组已经加入到了 R 的变量里");
StringBuffer sb = new StringBuffer();
StringBuffer cbind = new StringBuffer();
cbind.append("matrix <- cbind(").append(OUTCOME_VARIABLE).append(",")
.append(StringUtils.join(covairateNames, ",")).append(")\n");
sb.append(cbind.toString());
sb.append("df <- as.data.frame(matrix)\n");
sb.append("library(MatchIt)\n");
String replaceStr = input.isReplacement() ? "TRUE" : "FALSE";
StringBuffer propensity = new StringBuffer();
propensity.append("fm <- matchit(").append(OUTCOME_VARIABLE).append(" ~ ")
.append(StringUtils.join(covairateNames, " + ")).append(", data = df, method = \"")
.append(input.getAlgorithm().getValue()).append("\", caliper = ").append(input.getCaliper())
.append(", replace = ").append(replaceStr).append(", ratio = ").append(input.getMatchRatio())
.append(")\n");
sb.append(propensity.toString());
sb.append("result <- summary(fm)\n");
sb.append("sum <- result$sum.all\n");
sb.append("mat <- result$sum.matched\n");
sb.append("red <- result$reduction\n");
sb.append("ss <- result$nn\n");
sb.append("mData <- match.data(fm)[1]\n");
sb.append("out <- list(sum, mat, red, ss, mData)\n");
String code = sb.toString();
logger.info("完整的 Match 算法的 R 程序:: \n {}", code);
REXP rexp = rc.eval(code);
logger.info("完成 Propensity Score Match 匹配逻辑");
return rexp.asList();
} catch (Exception e) {
logger.error(e.getMessage());
throw new RuntimeException("执行 Propensity Score Match 匹配出错了");
}
}
将变量值数组传入 Rserve 里使用 assign 函数,对于独立的语句比如 “library(MatchIt)” 也可以直接使用:
rc.eval("library(MatchIt)");这里我将多条语句放入缓存池,然后一起 eval , 注意:需要在每一行末尾加上换行符,模拟命令行的执行。执行完,从 list 里面取出各个对象:
logger.info("将 Map 对象里的数据注入到 R 程序里,同时执行 R 的匹配算法");
RList result = exeRMatchCode(input, varResultMap, covairateNames);
logger.info("从 R 的匹配结果里取出需要的数据,放入到 R 对应的 java 对象备用");
REXPGenericVector sumAllVector = (REXPGenericVector)result.elementAt(0);
REXPGenericVector matchedVector = (REXPGenericVector)result.elementAt(1);
REXPGenericVector balImproveVector = (REXPGenericVector)result.elementAt(2);
REXPDouble sampleSize = (REXPDouble)result.elementAt(3);
REXPGenericVector matchedPersonsVector = (REXPGenericVector)result.elementAt(4);
下面就挑其中一个来看看,怎么获取每个具体的值:
// 由于 R 对应的对象在取 R 矩阵的值,读取是先列后行,所有数据处理比较特殊
private Collection<PropensitySum> extractMatchVectorData(REXPGenericVector vector,
LinkedList<String> variableNamesR) {
LinkedHashMap<String, PropensitySum> map = new LinkedHashMap<>();
for (String name : variableNamesR){
map.put(name, new PropensitySum());
}
RList t = vector.asList();
Vector names = t.names;
for (int i = 0; i < names.size(); i++){
String name = ((String)names.get(i)).trim();
double[] vals = ((REXPDouble)t.elementAt(i)).asDoubles();
if ("Means Treated".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).setMeansTreated(vals[j]);
}
} else if ("Means Control".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).setMeansControl(vals[j]);
}
} else if ("SD Control".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).setSdControl(vals[j]);
}
} else if (name.startsWith("Mean Diff")){ // 这个列名比较特殊, Bal Improve 矩阵这个列名后面有个点号
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).setMeanDiff(vals[j]);
}
} else if ("eQQ Med".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).seteQQMed(vals[j]);
}
} else if ("eQQ Mean".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).seteQQMean(vals[j]);
}
} else if ("eQQ Max".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).seteQQMax(vals[j]);
}
}
}
return map.values();
}
可以看到,有强转型,有数组下标取值,就这两个就觉得程序耦合性太高了。总之,感觉 API 不够友好,没有跟上潮流啊。
使用下来的感觉是 Rserve 虽然能把值都给你,但是怎么获取却是一个艰难的过程,比如和 RCaller 一样,对矩阵值的读取也是先列后行,定位到具体的值的变量上,API 显然没有与时俱进,不用泛型,使用古老的 Vector 类型,经常要强制转型,要不是 debug, 我怎么知道那个列是什么数据类型啊。
private RList exeRMatchCode(PropensityMatchInput input, Map<String, List<String>> varResultMap,
List<String> covairateNames) {
logger.info("entering exeRMatchCode()");
try {
RConnection rc = new RConnection();
for (String key : varResultMap.keySet()){
logger.info("key is :: {}", key);
List<String> varVals = varResultMap.get(key);
String[] valStrs = new String[varVals.size()];
int num = 0;
for (String s : varVals){
valStrs[num++] = s;
}
rc.assign(key, valStrs);
}
logger.info("各个变量值的数组已经加入到了 R 的变量里");
StringBuffer sb = new StringBuffer();
StringBuffer cbind = new StringBuffer();
cbind.append("matrix <- cbind(").append(OUTCOME_VARIABLE).append(",")
.append(StringUtils.join(covairateNames, ",")).append(")\n");
sb.append(cbind.toString());
sb.append("df <- as.data.frame(matrix)\n");
sb.append("library(MatchIt)\n");
String replaceStr = input.isReplacement() ? "TRUE" : "FALSE";
StringBuffer propensity = new StringBuffer();
propensity.append("fm <- matchit(").append(OUTCOME_VARIABLE).append(" ~ ")
.append(StringUtils.join(covairateNames, " + ")).append(", data = df, method = \"")
.append(input.getAlgorithm().getValue()).append("\", caliper = ").append(input.getCaliper())
.append(", replace = ").append(replaceStr).append(", ratio = ").append(input.getMatchRatio())
.append(")\n");
sb.append(propensity.toString());
sb.append("result <- summary(fm)\n");
sb.append("sum <- result$sum.all\n");
sb.append("mat <- result$sum.matched\n");
sb.append("red <- result$reduction\n");
sb.append("ss <- result$nn\n");
sb.append("mData <- match.data(fm)[1]\n");
sb.append("out <- list(sum, mat, red, ss, mData)\n");
String code = sb.toString();
logger.info("完整的 Match 算法的 R 程序:: \n {}", code);
REXP rexp = rc.eval(code);
logger.info("完成 Propensity Score Match 匹配逻辑");
return rexp.asList();
} catch (Exception e) {
logger.error(e.getMessage());
throw new RuntimeException("执行 Propensity Score Match 匹配出错了");
}
}
将变量值数组传入 Rserve 里使用 assign 函数,对于独立的语句比如 “library(MatchIt)” 也可以直接使用:
rc.eval("library(MatchIt)");这里我将多条语句放入缓存池,然后一起 eval , 注意:需要在每一行末尾加上换行符,模拟命令行的执行。执行完,从 list 里面取出各个对象:
logger.info("将 Map 对象里的数据注入到 R 程序里,同时执行 R 的匹配算法");
RList result = exeRMatchCode(input, varResultMap, covairateNames);
logger.info("从 R 的匹配结果里取出需要的数据,放入到 R 对应的 java 对象备用");
REXPGenericVector sumAllVector = (REXPGenericVector)result.elementAt(0);
REXPGenericVector matchedVector = (REXPGenericVector)result.elementAt(1);
REXPGenericVector balImproveVector = (REXPGenericVector)result.elementAt(2);
REXPDouble sampleSize = (REXPDouble)result.elementAt(3);
REXPGenericVector matchedPersonsVector = (REXPGenericVector)result.elementAt(4);
下面就挑其中一个来看看,怎么获取每个具体的值:
// 由于 R 对应的对象在取 R 矩阵的值,读取是先列后行,所有数据处理比较特殊
private Collection<PropensitySum> extractMatchVectorData(REXPGenericVector vector,
LinkedList<String> variableNamesR) {
LinkedHashMap<String, PropensitySum> map = new LinkedHashMap<>();
for (String name : variableNamesR){
map.put(name, new PropensitySum());
}
RList t = vector.asList();
Vector names = t.names;
for (int i = 0; i < names.size(); i++){
String name = ((String)names.get(i)).trim();
double[] vals = ((REXPDouble)t.elementAt(i)).asDoubles();
if ("Means Treated".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).setMeansTreated(vals[j]);
}
} else if ("Means Control".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).setMeansControl(vals[j]);
}
} else if ("SD Control".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).setSdControl(vals[j]);
}
} else if (name.startsWith("Mean Diff")){ // 这个列名比较特殊, Bal Improve 矩阵这个列名后面有个点号
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).setMeanDiff(vals[j]);
}
} else if ("eQQ Med".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).seteQQMed(vals[j]);
}
} else if ("eQQ Mean".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).seteQQMean(vals[j]);
}
} else if ("eQQ Max".equalsIgnoreCase(name)){
for (int j = 0; j < vals.length; j++){
map.get(variableNamesR.get(j)).seteQQMax(vals[j]);
}
}
}
return map.values();
}
可以看到,有强转型,有数组下标取值,就这两个就觉得程序耦合性太高了。总之,感觉 API 不够友好,没有跟上潮流啊。
相关文章推荐
- Android:使用AIDL实现进程间传递复杂数据类型
- 走进C++程序世界-------类的定义和使用(数据成员和方法成员,析构函数,构造函数,内联实现)
- 【Android】使用Intent实现数据传递之返回结果
- android开发(26) 和其他应用交换数据方式一,使用intent指定自定义action调用其他程序里的activity,并获得其返回的结果
- Android开发:使用序列化接口Parcelable、Serializable实现Activity间传递复杂数据类型参数
- 利用AJAX实现简单的用户登录程序(处理服务端返回的文本数据)
- 九宫格 Swift提供经典的数组和字典两种集合类型来存储集合数据,使用数组实现一个九宫格程序,
- Android开发:使用序列化接口Parcelable、Serializable实现Activity间传递复杂数据类型参数
- 使用序列化接口Parcelable、Serializable实现Activity间传递复杂数据类型参数
- 使用代码块和JAVA程序来接收游标返回数据集合
- Android使用ScrollView嵌套ListView实现复杂数据列表选择处理
- SSH框架实现返回json数据,并使用android app进行访问
- struts2学习笔记--使用struts2插件实现ajax处理(返回json数据)
- android开发(26) 和其他应用交换数据方式一,使用intent指定自定义action调用其他程序里的activity,并获得其返回的结果
- 使用ASP.NET一般处理程序或WebService返回JSON的实现代码
- 字符串处理是许多程序中非常重要的一部分,它们可以用于文本显示,数据表示,查找键和很多目的.在Unix下,用户可以使用正则表达式的强健功能实现这些 目的,从Java1.4起,Java核心API就引入了java.util.regex程序包,它是一种有价值的基础
- [python]使用python实现Hadoop MapReduce程序:计算一组数据的均值和方差
- android开发(26) 和其他应用交换数据方式一,使用intent指定自定义action调用其他程序里的activity,并获得其返回的结果
- IBatis.Net使用总结(三)-- IBatis实现分页返回数据和总数
- java 大量数据提交时,使用队列定时提交思路的程序实现