apache-spark apache-spark-sql distinct-values

apache spark - Spark DataFrame: cuente valores distintos de cada columna



apache-spark apache-spark-sql (5)

Agregando a la respuesta de desaiankitb, esto le proporcionaría una respuesta más intuitiva:

del pyspark.sql.functions importación de pyspark.sql.functions

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

La pregunta está más o menos en el título: ¿Hay una manera eficiente de contar los valores distintos en cada columna en un DataFrame?

El método describe proporciona solo el recuento, pero no el recuento distinto, y me pregunto si hay una manera de obtener el recuento distinto para todas las columnas (o algunas seleccionadas).


En pySpark podría hacer algo como esto, usando countDistinct() :

from pyspark.sql.functions import col, countDistinct df.agg(*(countDistinct(col(c)).alias(c) for c in df.columns))

De manera similar en 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)): _*)

Si desea acelerar las cosas ante la posible pérdida de precisión, también puede usar approxCountDistinct() .


Las agregaciones múltiples serían bastante caras de calcular. Sugiero que utilice métodos de aproximación en su lugar. En este caso, recuento distinto aproximado:

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| // +---------------------------+---------------------------+---------------------------+

El método approx_count_distinct se basa en HyperLogLog debajo del capó.

El algoritmo HyperLogLog y su variante HyperLogLog ++ (implementado en Spark) se basa en la siguiente observación inteligente .

Si los números se distribuyen uniformemente en un rango, entonces el recuento de elementos distintos se puede aproximar a partir del mayor número de ceros iniciales en la representación binaria de los números.

Por ejemplo, si observamos un número cuyos dígitos en forma binaria son de la forma 0…(k times)…01…1 , entonces podemos estimar que hay en el orden de 2 ^ k elementos en el conjunto. Esta es una estimación muy cruda, pero se puede refinar con gran precisión con un algoritmo de dibujo.

Se puede encontrar una explicación detallada de la mecánica detrás de este algoritmo en el documento original .

Nota: Al iniciar Spark 1.6 , cuando Spark llama a SELECT SOME_AGG(DISTINCT foo)), SOME_AGG(DISTINCT bar)) FROM df cada cláusula debe activar una agregación separada para cada cláusula. Mientras que esto es diferente de SELECT SOME_AGG(foo), SOME_AGG(bar) FROM df donde SELECT SOME_AGG(foo), SOME_AGG(bar) FROM df una vez. Por lo tanto, el rendimiento no será comparable cuando se utiliza un count(distinct(_)) y approxCountDistinct (o approx_count_distinct ).

Es uno de los cambios de comportamiento desde Spark 1.6 :

Con el planificador de consultas mejorado para consultas que tienen agregaciones distintas (SPARK-9241), el plan de una consulta que tiene una única agregación distinta se ha cambiado a una versión más robusta. Para volver al plan generado por el planificador de Spark 1.5, establezca spark.sql.specializeSingleDistinctAggPlanning en verdadero. (SPARK-12077)

Referencia: Algoritmos aproximados en Apache Spark: HyperLogLog y Quantiles .


Puede usar la función de count(column name) de SQL

Alternativamente, si está utilizando el análisis de datos y desea una estimación aproximada y no un recuento exacto de todas y cada una de las columnas, puede usar la función approx_count_distinct(expr[, relativeSD])


Si solo desea contar para una columna en particular, lo siguiente podría ayudar. Aunque es una respuesta tardía. Puede ayudar a alguien. ( pyspark 2.2.0 probado)

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