Sparkデータフレーム(PySparkを使用)でグループ変位値を計算したいです。近似または正確な結果で問題ありません。groupBy
/agg
なので、他のPySpark集計関数と混合できますが、これが何らかの理由で不可能な場合は、別のアプローチでも問題ありません。
この質問 は関連していますが、approxQuantile
を集約関数として使用する方法を示していません。
percentile_approx
Hive UDFにもアクセスできますが、それを集計関数として使用する方法がわかりません。
特異性のために、次のデータフレームがあると仮定します。
from pyspark import SparkContext
import pyspark.sql.functions as f
sc = SparkContext()
df = sc.parallelize([
['A', 1],
['A', 2],
['A', 3],
['B', 4],
['B', 5],
['B', 6],
]).toDF(('grp', 'val'))
df_grp = df.groupBy('grp').agg(f.magic_percentile('val', 0.5).alias('med_val'))
df_grp.show()
期待される結果は次のとおりです。
+----+-------+
| grp|med_val|
+----+-------+
| A| 2|
| B| 5|
+----+-------+
もう必要ないでしょう。しかし、将来の世代のためにここに残します(つまり、来週忘れたとき)。
from pyspark.sql import Window
import pyspark.sql.functions as F
grp_window = Window.partitionBy('grp')
magic_percentile = F.expr('percentile_approx(val, 0.5)')
df.withColumn('med_val', magic_percentile.over(grp_window))
またはあなたの質問に正確に対処するために、これも機能します:
df.groupBy('gpr').agg(magic_percentile.alias('med_val'))
ボーナスとして、パーセンタイルの配列を渡すことができます:
quantiles = F.expr('percentile_approx(val, array(0.25, 0.5, 0.75))')
そして、あなたは見返りにリストを取得します。
percentile_approx
にアクセスできるので、簡単な解決策の1つはSQL
コマンドで使用することです。
from pyspark.sql import SQLContext
sqlContext = SQLContext(sc)
df.registerTempTable("df")
df2 = sqlContext.sql("select grp, percentile_approx(val, 0.5) as med_val from df group by grp")
残念ながら、私の知る限り、「純粋な」PySparkコマンドを使用してこれを行うことはできないようです(ShaidoのソリューションはSQLの回避策を提供します)。その理由は非常に基本的です。 mean
、approxQuantile
などの関数はColumn
型を返しませんが、list 。
サンプルデータの簡単な例を見てみましょう。
spark.version
# u'2.2.0'
import pyspark.sql.functions as func
from pyspark.sql import DataFrameStatFunctions as statFunc
# aggregate with mean works OK:
df_grp_mean = df.groupBy('grp').agg(func.mean(df['val']).alias('mean_val'))
df_grp_mean.show()
# +---+--------+
# |grp|mean_val|
# +---+--------+
# | B| 5.0|
# | A| 2.0|
# +---+--------+
# try aggregating by median:
df_grp_med = df.groupBy('grp').agg(statFunc(df).approxQuantile('val', [0.5], 0.1))
# AssertionError: all exprs should be Column
# mean aggregation is a Column, but median is a list:
type(func.mean(df['val']))
# pyspark.sql.column.Column
type(statFunc(df).approxQuantile('val', [0.5], 0.1))
# list
私が言ったように、根本的な理由は非常に基本的なものであるため、ウィンドウベースのアプローチが何らかの違いを生むとは思わない。
詳細については my answer here も参照してください。