Spark DataFrame:计算每列的不同值

时间:2016-11-30 12:55:28

标签: apache-spark apache-spark-sql distinct-values

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

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

5 个答案:

答案 0 :(得分:31)

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()

答案 1 :(得分:29)

多次聚合计算起来非常昂贵。我建议您使用近似方法。在这种情况下,接近不同的计数:

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 以来行为的更改之一:

  

使用针对具有不同聚合的查询的改进查询规划器(SPARK-9241),具有单个不同聚合的查询的计划已被更改为更健壮的版本。要切换回Spark 1.5的计划程序生成的计划,请将spark.sql.specializeSingleDistinctAggPlanning设置为true。 (SPARK-12077)

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

答案 2 :(得分:5)

如果您只想计算特定列,则可以提供以下帮助。虽然它的回答很晚。它可能对某人有帮助。 (pyspark 2.2.0已测试)

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

答案 3 :(得分:0)

您可以使用SQL的count(column name)函数

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

答案 4 :(得分:-1)

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

来自pyspark.sql.functions的导入计数

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