计算Spark DataFrame中的非空值的数量

时间:2017-01-20 14:18:16

标签: scala apache-spark-sql

我有一些带有一些列的数据框,在进行分析之前,我想了解这样的数据帧是如何完整的,所以我想过滤数据帧并计算每列的非数量null值,可能返回一个数据帧。

基本上,我试图获得与this question中表达的相同的结果,但使用Scala而不是Python ......

说你有:

val row = Row("x", "y", "z")
val df = sc.parallelize(Seq(row(0, 4, 3), row(None, 3, 4), row(None, None, 5))).toDF()

如何总结每列的非空数并返回具有相同列数的数据帧,只返回一行的答案?

4 个答案:

答案 0 :(得分:7)

一个直接的选择是使用.describe()函数来获取数据框的摘要,其中count行包含非空值的计数:

df.describe().filter($"summary" === "count").show
+-------+---+---+---+
|summary|  x|  y|  z|
+-------+---+---+---+
|  count|  1|  2|  3|
+-------+---+---+---+

答案 1 :(得分:3)

虽然我喜欢Psidoms的答案,但我常常对空值的分数更感兴趣,因为只有非空值的数量并不多...

您可以执行以下操作:

import org.apache.spark.sql.functions.{sum,when, count}

df.agg(
   (sum(when($"x".isNotNull,0).otherwise(1))/count("*")).as("x : fraction null"),
   (sum(when($"y".isNotNull,0).otherwise(1))/count("*")).as("y : fraction null"),
   (sum(when($"z".isNotNull,0).otherwise(1))/count("*")).as("z : fraction null")
 ).show()

编辑:sum(when($"x".isNotNull,0).otherwise(1))也可以由count($"x")替换,sum仅计算非空值。当我发现这不明显时,我倾向于使用更清晰的var data, filteredData, testDate = new Date("2017-01-14T02:00:00Z"); data = [ { "_id": "58816d03e4b00654468d2781", "datetime": "2017-01-03T05:23:02Z", "msg": "foo1", "msg2": "foo2" }, { "_id": "58816d03e4b00654468d2963", "datetime": "2017-01-14T01:50:52Z", "msg": "foo1", "msg2": "foo2" }, { "_id": "58816d03e4b00654468d3068", "datetime": "2017-01-16T13:41:46Z", "msg": "foo1", "msg2": "foo2" }, { "_id": "58816d03e4b00654468d3068", "datetime": "2017-01-20T21:16:40Z", "msg": "foo1", "msg2": "foo2" } ] filteredData = data.filter(function(d){ return new Date(d.datetime) > testDate; }); 符号

答案 2 :(得分:1)

这是我在Scala 2.11,Spark 2.3.1中进行的操作:

import org.apache.spark.sql.functions._
import org.apache.spark.sql.types._

df.agg(
    count("x").divide(count(lit(1)))
        .as("x: percent non-null")
    // ...copy paste that for columns y and z
).head()

count(*)计算非空行,count(1)在每一行上运行。

如果您想计算人口中空的的百分比,请找到我们基于计数的方程的补数:

lit(1).minus(
    count("x").divide(count(lit(1)))
    )
    .as("x: percent null")

值得一提的是,您可以将无效性强制转换为整数,然后求和
但这可能表现不佳:

// cast null-ness to an integer
sum(col("x").isNull.cast(IntegerType))
    .divide(count(lit(1)))
    .as("x: percent null")

答案 3 :(得分:0)

这是最简单的查询:

d.filter($"x" !== null ).count