我有一个包含一些列的数据框,在进行分析之前,我想了解数据框的完整性。因此,我想过滤数据框并计算每列的非空值数量,可能会返回数据帧。
基本上,我试图达到与这个问题中表达的相同的结果,但使用 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()
如何汇总每列的非空值数,并返回具有相同列数且仅包含答案的单行的数据帧?
一个简单的选项是使用 .describe()
函数获取数据框的摘要,其中计数行包含非空值的计数:
df.describe().filter($"summary" === "count").show
+-------+---+---+---+
|summary| x| y| z|
+-------+---+---+---+
| count| 1| 2| 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
表示法
以下是我在 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")
同样值得一提的是,您可以将 nullness 转换为整数,然后将其求和。
但它的性能可能较差:
// cast null-ness to an integer
sum(col("x").isNull.cast(IntegerType))
.divide(count(lit(1)))
.as("x: percent null")
这是最简单的查询:
d.filter($"x" !== null ).count
df.select(df.columns map count: _*)
或
df.select(df.columns map count: _*).toDF(df.columns: _*)
Spark 2.3+
(对于字符串和数字类型列)
df.summary("count").show()
+-------+---+---+---+
|summary| x| y| z|
+-------+---+---+---+
| count| 1| 2| 3|
+-------+---+---+---+