如何将“任意列表”类型转换为“双精度(斯卡拉)”类型

时间:2019-04-23 23:53:36

标签: scala apache-spark mean databricks

我是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类型,但是这种情况显然没有发生。

现在让问题开始:

  1. map(_(0)) do是什么?我知道map()转换的基本定义,但我找不到确切的解释

  2. 我知道,通过在命令末尾使用.toList方法,我的结果将是类型为Any的列表。有没有办法将其更改为包含类型Double元素的List?甚至转换成这个

  3. 您认为将Dataframe的列传递到List [Double]然后计算其元素的平均值是否更合适?

  4. 根据我的问题,我上面显示的解决方案在任何角度都正确吗?我知道“正在运行”与“正确的解决方案”不同吗?

总结一下,我需要计算数据框某一列的平均值,并将结果作为双精度类型变量。

请注意:我是希腊人,有时候我很难理解一些英语编码的“ s语”。

2 个答案:

答案 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