我有一个Spark DataFrame(df),如下所示:
+----------+--------+----------+--------+
| c1| c2| c3| c4|
+----------+--------+----------+--------+
| 1 | 5 | null| 7 |
+----------+--------+----------+--------+
| 1 | 5 | 4 | 8 |
+----------+--------+----------+--------+
| 1 | 3 | null| 11 |
+----------+--------+----------+--------+
| 1 | 3 | null| null |
+----------+--------+----------+--------+
| 2 | 6 | 23 | 17 |
+----------+--------+----------+--------+
| 2 | 6 | 7 | 3 |
+----------+--------+----------+--------+
| 2 | 3 | null| 11 |
+----------+--------+----------+--------+
| 2 | 3 | null| 17 |
+----------+--------+----------+--------+
我希望使用(c1,c2)
作为关键字进行汇总,并average
c3
和c4
,以便我拥有:
+----------+--------+----------+--------+
| c1| c2| c3| c4|
+----------+--------+----------+--------+
| 1 | 5 | 4 | 7.5 |
+----------+--------+----------+--------+
| 1 | 3 | null| 11 |
+----------+--------+----------+--------+
| 2 | 6 | 15 | 10 |
+----------+--------+----------+--------+
| 2 | 3 | null| 14 |
+----------+--------+----------+--------+
所以,基本上我忽略了null
值。
我的半生不熟的代码如下所示:
val df1 = df.
// just working on c3 for time being
map(x => ((x.getInt(0), x.getInt(1)), x.getDouble(3))).
reduceByKey(
(x, y) => {
var temp = 0
var sum = 0.0
var flag = false
if (x == null) {
if (y != null) {
temp = temp + 1
sum = y
flag = true
}
} else {
if (y == null) {
temp = temp + 1
sum = x
} else {
temp = temp + 1
sum = x + y
flag = true
}
}
if (flag == false) {
null
} else {
sum/temp
}
}
)
显然,上面的代码不起作用。任何帮助使代码工作的人都非常感激。
编辑1 @ zero232给出的答案是一个解决方案。但是,它不是我正在寻找的“解决方案”。我的兴趣是在为reduceByKey()
编写自定义函数时理解如何处理空值。 我正在重新询问以下问题:
我希望使用(c1,c2)
作为关键字进行汇总,并root mean square
[{sum(a_i ^ 2)} ^ 0.5](或某些函数在火花中不可用){忽略空值时{1}}和c3
,所以我有这个:
c4
答案 0 :(得分:3)
只需groupBy
并使用mean
:
df.groupBy("c1", "c2").mean("c3", "c4")
或agg
df.groupBy("c1", "c2").agg(avg("c3"), avg("c4"))
通常DataFrames
上的所有原始函数都会正确处理null
值。
import org.apache.spark.sql.functions._
def rms(c: String) = sqrt(avg(pow(col(c), 2))).alias(s"rms($c)")
df.groupBy("c1", "c2").agg(rms("c3"), rms("c4"))
如果您想忽略null
RDDs
,请在应用缩减之前将其过滤掉:
somePairRDD.filter(_._2 != null)
.foldByKey(someDefualtValue)(someReducingFunction)
或将值转换为Option
并使用模式匹配:
somePairRDD.mapValues(Option(_)).reduceByKey {
case (Some(x), Some(y)) => doSomething(x, y)
case (Some(x), _) => doSomething(x)
case (_, Some(_)) => doSomething(y)
case _ => someDefualt
}
或使用map
/ flatMap
/ getOrElse
和其他标准工具来处理未定义的值。