业务场景中,我们可能会碰到这样的情况:每一条数据有好几个列都是数值,比如不同科目的分数。而我们需要计算每一个数值列的最大值、最小值、标准差、方差之类的。这种情况下,如果在使用groupby分组聚合的时候,依次去对每一列进行聚合,就会导致写了非常多重复的代码。例如:
df.groupby("name").agg(F.stddev("val1"),F.stddev("val2"),F.stddev("val3")).show()
如果需要计算的维度特别多就会导致代码很长,而且多了很多冗余的代码。而将同类型的聚合放到一个表达式中则可以使代码简洁不少:
expressions = [F.stddev(col).alias('%s_std'%(col)) for col in ['a_score','b_score']]
打印expressions可以得到:
[Column<b'stddev_samp(a_score) AS `a_score_std`'>, Column<b'stddev_samp(b_score) AS `b_score_std`'>]
这是一个列组成的列表,每个列又是一个函数表达式,而且覆盖到了所需要的所有列。
完整的代码如下:
from pyspark.sql import Row
from pyspark.sql.window import Window
from pyspark.sql.functions import mean, col
from pyspark.sql import functions as F
col_names = ["name", "a_score", "b_score"]
value = [
("Ali", 20, 10.0),
("Ali", 30, 15.0),
("Ali", 15, 20.0),
("Ali", 20, 25.0),
("Ali", 10, 30.0),
("Bob", 20, 15.0),
("Bob", 15, 20.0),
("Bob", 10, 30.0)
]
df = spark.createDataFrame(value, col_names)
df.show()
expressions = [F.stddev(col).alias('%s_std'%(col)) for col in ['a_score','b_score']]
print(expressions)
df.groupby('name').agg(*expressions).show()
结果如下:
+----+-------+-------+
|name|a_score|b_score|
+----+-------+-------+
| Ali| 20| 10.0|
| Ali| 30| 15.0|
| Ali| 15| 20.0|
| Ali| 20| 25.0|
| Ali| 10| 30.0|
| Bob| 20| 15.0|
| Bob| 15| 20.0|
| Bob| 10| 30.0|
+----+-------+-------+
[Column<b'stddev_samp(a_score) AS `a_score_std`'>, Column<b'stddev_samp(b_score) AS `b_score_std`'>]
+----+-----------------+-----------------+
|name| a_score_std| b_score_std|
+----+-----------------+-----------------+
| Bob| 5.0|7.637626158259733|
| Ali|7.416198487095663|7.905694150420949|
+----+-----------------+-----------------+