我正在尝试计算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
答案 0 :(得分:7)
从Spark2.0开始,事情变得越来越容易,只需在DataFrameStatFunctions中使用此函数,如:
df.stat.approxQuantile("Open_Rate",Array(0.25,0.50,0.75),0.0)
DataFrameStatFunctions中的DataFrame也有一些有用的统计函数。
答案 1 :(得分:4)
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)。因此,如果代码可能在同一个集群上同时运行多次,则应使用随机表名。
在我的团队中,模式很常见,我们在.sql()
中添加了一个隐含的DataFrame
,它会自动注册然后取消注册SQL语句范围的临时表。
答案 2 :(得分:0)
我创建了一个 bebe 库,可以轻松计算列的百分位数。
让我们从创建您的 DataFrame 开始。
val df = spark
.createDF(
List(
("A1", 10.3),
("B1", 4.04),
("C1", 21.7),
("D1", 18.6)
),
List(
("User ID", StringType, true),
("Open_Rate", DoubleType, true)
)
)
df.show()
+-------+---------+
|User ID|Open_Rate|
+-------+---------+
| A1| 10.3|
| B1| 4.04|
| C1| 21.7|
| D1| 18.6|
+-------+---------+
现在让我们计算第 10 个百分位数:
val resDF = df.agg(bebe_percentile(col("Open_Rate"), lit(0.1)).as("10_percentile"))
resDF.show()
+-----------------+
| 10_percentile|
+-----------------+
|5.918000000000001|
+-----------------+
它使用与 the SQL percentile method 相同的底层代码。