web-dev-qa-db-ja.com

SparkのDataFrameの列のパーセンタイルを計算する方法は?

DataFrameの列のパーセンタイルを計算しようとしていますか? Spark集計関数にpercentile_approx関数が見つかりません。

例: Hiveにはpercentile_approxがあり、次のように使用できます

hiveContext.sql("select percentile_approx("Open_Rate",0.10) from myTable); 

しかし、パフォーマンス上の理由から、Spark DataFrameを使用して実行したいと思います。

サンプルデータセット

|User ID|Open_Rate|
------------------- 
|A1     |10.3     |
|B1     |4.04     |
|C1     |21.7     |
|D1     |18.6     |

10パーセンタイルや20パーセンタイルなどに分類されるユーザーの数を知りたいです。こんなことしたい

df.select($"id",Percentile($"Open_Rate",0.1)).show
10
dheee

Spark2.0以降、作業が簡単になりました。次のようなDataFrameStatFunctionsでこの関数を使用するだけです。

df.stat.approxQuantile("Open_Rate",Array(0.25,0.50,0.75),0.0)

DataFrameStatFunctionsには、DataFrameに役立つ統計関数もいくつかあります。

7
Yulin GUO

SparkSQLとScalaデータフレーム/データセットAPIは同じエンジンで実行されます。同等の操作で同等の実行プランが生成されます。実行プランはexplainで確認できます。

_sql(...).explain
df.explain
_

特定の質問になると、SparkSQLとScala DSL構文を混在させるのが一般的なパターンです。これは、ご存知のとおり、それらの機能はまだ同等ではないためです(別の例は、 SQLのexplode()とDSLのexplode()。後者はより強力ですが、マーシャリングのために非効率的です。)

それを行う簡単な方法は次のとおりです。

_df.registerTempTable("tmp_tbl")
val newDF = sql(/* do something with tmp_tbl */)
// Continue using newDF with Scala DSL
_

簡単な方法を使用する場合に留意する必要があるのは、一時テーブル名がクラスターグローバル(最大1.6.x)であるということです。したがって、コードが同じクラスター上で複数回同時に実行される可能性がある場合は、ランダム化されたテーブル名を使用する必要があります。

私のチームでは、パターンは一般的です-DataFrameに暗黙の.sql()を追加しました。これにより、SQLステートメントのスコープの一時テーブルが自動的に登録および登録解除されます。

4
Sim