Spark DataFrame:计算每列的不同值

Spark DataFrame: count distinct values of every column

标题中的问题差不多:是否有一种有效的方法来计算 DataFrame 中每一列中的不同值?

describe方法只提供计数,不提供非重复计数,我想知道是否有办法获取所有(或某些选定的)列的非重复计数。

pySpark 中你可以做这样的事情,使用 countDistinct():

from pyspark.sql.functions import col, countDistinct

df.agg(*(countDistinct(col(c)).alias(c) for c in df.columns))

Scala 类似:

import org.apache.spark.sql.functions.countDistinct
import org.apache.spark.sql.functions.col

df.select(df.columns.map(c => countDistinct(col(c)).alias(c)): _*)

如果您想加快速度,但可能会降低准确性,您也可以使用 approxCountDistinct()

多个聚合的计算成本非常高。我建议您改为使用近似方法。在这种情况下,近似不同计数:

val df = Seq((1,3,4),(1,2,3),(2,3,4),(2,3,5)).toDF("col1","col2","col3")

val exprs = df.columns.map((_ -> "approx_count_distinct")).toMap
df.agg(exprs).show()
// +---------------------------+---------------------------+---------------------------+
// |approx_count_distinct(col1)|approx_count_distinct(col2)|approx_count_distinct(col3)|
// +---------------------------+---------------------------+---------------------------+
// |                          2|                          2|                          3|
// +---------------------------+---------------------------+---------------------------+

approx_count_distinct 方法在底层依赖于 HyperLogLog

HyperLogLog 算法及其变体 HyperLogLog++(在 Spark 中实现)依赖于以下 聪明 观察。

如果数字在一个范围内均匀分布,则可以根据数字的二进制表示中前导零的最大数量来近似计算不同元素的数量。

例如,如果我们观察到一个数字,其二进制形式的数字是0…(k times)…01…1形式,那么我们可以估计集合中有2^k个元素。这是一个非常粗略的估计,但可以使用草图算法将其细化到非常精确的程度。

可以在 original paper.

中找到有关此算法背后机制的详尽解释

注意:Spark 1.6 开始,当 Spark 调用 SELECT SOME_AGG(DISTINCT foo)), SOME_AGG(DISTINCT bar)) FROM df 时,每个子句应该为每个子句触发单独的聚合。而这与我们聚合一次的 SELECT SOME_AGG(foo), SOME_AGG(bar) FROM df 不同。因此,当使用 count(distinct(_))approxCountDistinct(或 approx_count_distinct)时,性能将无法比较。

这是自 Spark 1.6 以来的行为变化之一:

With the improved query planner for queries having distinct aggregations (SPARK-9241), the plan of a query having a single distinct aggregation has been changed to a more robust version. To switch back to the plan generated by Spark 1.5’s planner, please set spark.sql.specializeSingleDistinctAggPlanning to true. (SPARK-12077)

参考:Approximate Algorithms in Apache Spark: HyperLogLog and Quantiles.

如果您只想对特定列进行计数,那么以下内容可能会有所帮助。虽然它的答案很晚。它可能会帮助某人。 (pyspark 2.2.0 已测试)

from pyspark.sql.functions import col, countDistinct
df.agg(countDistinct(col("colName")).alias("count")).show()

可以使用SQL

count(column name)功能

或者,如果您正在使用数据分析并且想要粗略估计而不是每一列的精确计数,您可以使用 approx_count_distinct 函数 approx_count_distinct(expr[, relativeSD])

添加到 desaiankitb 的答案中,这将为您提供更直观的答案:

from pyspark.sql.functions import count

df.groupBy(colname).count().show()