背景:当您的 R 代码从 Spark 后端请求某些计算的结果时,Spark 会执行计算并序列化结果。然后,该结果在 R 端反序列化,您将获得 R 对象。
现在,它在 Spark 后端的工作方式是——如果它计算出要返回的对象的类型是以下之一Character
, String
, Long
, Float
, Double
Integer
, Boolean
, Date
, TimeStamp
或他们的Array
等等,然后它序列化该对象。但是,如果它发现该类型与其中任何一个都不匹配,它只需为该对象分配一个 id,根据该 id 将其存储在内存中,然后将该 id 发送到 R 客户端。 (JVMObjectTracker
in R后端处理程序负责跟踪 Spark 后端上的 jvm 对象。)然后将其反序列化为jobjR 端的类。 (你可以看看writeObject
的方法德斯卡拉序列以全面了解哪些内容已预先序列化,哪些内容未序列化。)
现在,在 R 侧,如果您查看中的对象probability
你的专栏predictions
数据框,你会观察到他们的班级是jobj
。如前所述,此类的对象充当 Spark 集群上保存的实际 Java 对象的代理。在这种特殊情况下,支持 java 类是org.apache.spark.mllib.linalg.DenseVector
。这是一个向量,因为它包含每个类别的概率。并且因为这个向量不是SerDe类支持的序列化类型之一,所以spark后端只是返回jobj
代理并存储这些DenseVector
内存中的对象,以便允许将来对其进行操作。
有了这个背景——您应该能够通过调用这些方法来获取 R 前端的概率值DenseVector
对象。目前看来,我认为这是唯一的办法。以下是适用于鸢尾花数据集的代码——
irisDf <- createDataFrame(sqlContext, iris)
irisDf$target <- irisDf$Species == 'setosa'
model <- glm(target ~ . , data = irisDf, family = "binomial")
summary(model)
predictions <- predict(model, newData = irisDf)
modelPrediction <- select(predictions, "probability")
localPredictions <- SparkR:::as.data.frame(predictions)
getValFrmDenseVector <- function(x) {
#Given it's binary classification there are just two elems in vector
a <- SparkR:::callJMethod(x$probability, "apply", as.integer(0))
b <- SparkR:::callJMethod(x$probability, "apply", as.integer(1))
c(a, b)
}
t(apply(localPredictions, 1, FUN=getValFrmDenseVector))
这样我就得到了两个类的以下概率输出——
[,1] [,2]
1 3.036612e-15 1.000000e+00
2 5.919287e-12 1.000000e+00
3 7.831827e-14 1.000000e+00
4 7.712003e-13 1.000000e+00
5 4.427117e-16 1.000000e+00
6 3.816329e-16 1.000000e+00
[...]
Note: SparkR:::
带前缀的函数不会导出到 SparkR 包命名空间中。因此请记住,您正在针对包私有实现进行编码。 (但我真的不知道如何才能实现这一点,除非 Spark 为其提供公共 API 支持。)