我是Scala的新手,我想了解一些基本知识。
首先,我需要计算 DataFrame 的某些列的平均值,并将结果用作双精度类型变量。
经过一些Internet研究,我能够计算平均值,并同时使用以下命令将其传递到列表类型Any :
val avgX_List = mainDataFrame.groupBy().agg(mean("_c1")).collect().map(_(0)).toList
其中“ _c1 ”是我的数据框的第二列。此行代码返回类型为 List [Any] 的列表。
要将结果传递到变量中,我使用了以下命令:
var avgX = avgX_List(0)
希望var avgX可以自动输入double类型,但是这种情况显然没有发生。
现在让问题开始:
map(_(0)) do
是什么?我知道map()
转换的基本定义,但我找不到确切的解释
我知道,通过在命令末尾使用.toList
方法,我的结果将是类型为Any
的列表。有没有办法将其更改为包含类型Double
元素的List?甚至转换成这个
您认为将Dataframe的列传递到List [Double]然后计算其元素的平均值是否更合适?
根据我的问题,我上面显示的解决方案在任何角度都正确吗?我知道“正在运行”与“正确的解决方案”不同吗?
总结一下,我需要计算数据框某一列的平均值,并将结果作为双精度类型变量。
请注意:我是希腊人,有时候我很难理解一些英语编码的“ s语”。
答案 0 :(得分:4)
map(_(0))
是map( (r: Row) => r(0) )
的快捷方式,而反过来又是map( (r: Row) => r.apply(0) )
的快捷方式。 apply
方法返回Any
,因此您丢失了正确的类型。尝试改用map(_.getAs[Double](0))
或map(_.getDouble(0))
。
收集该列的所有条目然后计算平均值会适得其反,因为您必须将大量数据发送到主节点,然后在该单个中央节点上进行所有计算。这与Spark的优势恰恰相反。
您也不需要collect(...).toList
,因为您可以直接访问第0个条目(从Array
还是List
获取都无关紧要)。由于无论如何都将所有内容折叠为一个Row
,因此可以通过稍微重新排序方法来完全摆脱map
步骤:
val avgX = mainDataFrame.groupBy().agg(mean("_c1")).collect()(0).getDouble(0)
使用first
方法可以编写得更短:
val avgX = mainDataFrame.groupBy().agg(mean("_c1")).first().getDouble(0)
答案 1 :(得分:1)
#Any dataType in Scala can't be directly converted to Double.
#Use toString & then toDouble on final captured result.
#Eg-
#scala> x
#res22: Any = 1.0
#scala> x.toString.toDouble
#res23: Double = 1.0
#Note- Instead of using map().toList() directly use (0)(0) to get the final value from your resultset.
#TestSample(Scala)-
val wa = Array("one","two","two")
val wrdd = sc.parallelize(wa,3).map(x=>(x,1))
val wdf = wrdd.toDF("col1","col2")
val x = wdf.groupBy().agg(mean("col2")).collect()(0)(0).toString.toDouble
#O/p-
#scala> val x = wdf.groupBy().agg(mean("col2")).collect()(0)(0).toString.toDouble
#x: Double = 1.0