Spark DataFrame: подсчитывать различные значения для каждого столбца

Вопрос в значительной степени относится к заголовку: есть ли эффективный способ подсчета различных значений в каждом столбце в DataFrame?

Метод describe предоставляет только счет, но не отдельный счет, и мне интересно, есть ли способ получить отдельный счет для всех (или некоторых выбранных) столбцов.

Ответ 1

Многочисленные агрегации были бы довольно дорогими для вычисления. Я предлагаю вместо этого использовать методы приближения. В этом случае приблизительный отчетливый счет:

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 элементов. Это очень грубая оценка, но ее можно уточнить с высокой точностью с помощью алгоритма зарисовки.

Подробное объяснение механизма, лежащего в основе этого алгоритма, можно найти в оригинальной статье.

Примечание. Начиная с 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.5s, установите для параметра spark.sql.specializeSingleDistinctAggPlanning значение true. (СПАРК-12077)

Ссылка: Приближенные алгоритмы в Apache Spark: HyperLogLog и Quantiles.

Ответ 2

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

Ответ 3

если вы просто хотите рассчитывать на конкретный столбец, то может помочь следующее. Хотя его поздний ответ. это может кому-то помочь. (протестирован pyspark 2.2.0)

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

Ответ 4

Если добавить ответ к desaiankitb, это даст вам более интуитивный ответ:

из pyspark.sql.functions счетчик импорта

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

Ответ 5

Вы можете использовать функцию count(column name) SQL

В качестве альтернативы, если вы используете анализ данных и хотите получить приблизительную оценку, а не точный подсчет каждого и каждого столбца, вы можете использовать функцию approx_count_distinct(expr[, relativeSD])

Ответ 6

Я хочу получить количество отдельных значений для нескольких столбцов из Dataframe с использованием Spark и Java8

Входной DataFrame - необходимо написать код для динамических столбцов - столбцы могут быть добавлены позже

+----+----+----+
|Col1|Col2|Col3|
+----+----+----+
|A1|Y|B2|Y|C3|Y|
|A1|Y|B2|N|C3|Y|
|A1|Y|B2|Y|C3|N|
+----+----+----+

Выходной DateFrame

+--------+---------------------+--------------------+
|Col1    | Col2                | Col3               |
+--------+---------------------+--------------------+
|A1|Y - 3| B2|Y - 2 & B2|N - 1 | C3|Y - 3 & C3|N -1 |
+----+----+----+----+----+----+----+----+----+------+