web-dev-qa-db-ja.com

Spark DataFrame:すべての列の異なる値をカウントする

問題はほとんどタイトルにあります:DataFrameのすべての列の個別の値をカウントする効率的な方法はありますか?

describe メソッドはカウントのみを提供し、個別のカウントは提供しません。すべての(または選択された)列の個別のカウントを取得する方法があるのでしょうか。

20
Rami

複数の集計は、計算にかなりの費用がかかります。代わりに近似法を使用することをお勧めします。この場合、個別のカウントの概算:

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以降の動作の変更の1つです

個別の集計を持つクエリの改善されたクエリプランナー(SPARK-9241)により、単一の個別の集計を持つクエリのプランがより堅牢なバージョンに変更されました。 Spark 1.5 ’プランナーによって生成されたプランに戻すには、spark.sql.specializeSingleDistinctAggPlanningをtrueに設定してください。 (SPARK-12077)

参照: Apache Sparkの近似アルゴリズム:HyperLogLogおよびQ​​uantiles

30
eliasah

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()を使用することもできます。

33
mtoto

特定の列だけを数えたい場合は、以下が役立ちます。その遅い答えが。それは誰かを助けるかもしれません。 (pyspark 2.2.0テスト済み)

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

Desaiankitbの答えに加えて、これはより直感的な答えを提供します:

from pyspark.sql.functionsインポートカウント

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

SQLのcount(column name)関数を使用できます

あるいは、データ分析を使用していて、各列の正確なカウントではなく大まかな推定が必要な場合は、approx_count_distinct関数approx_count_distinct(expr[, relativeSD])を使用できます

0
Ahmed