Pyspark 数据框:计算数组或列表中的元素

All*_*ati 6 arrays list counting dataframe pyspark

让我们假设数据帧df为:

df.show()
Run Code Online (Sandbox Code Playgroud)

输出:

+------+----------------+
|letter| list_of_numbers|
+------+----------------+
|     A|    [3, 1, 2, 3]|
|     B|    [1, 2, 1, 1]|
+------+----------------+
Run Code Online (Sandbox Code Playgroud)

我想要做的是对countcolumn 中特定元素的编号list_of_numbers。像这样的东西:

+------+----------------+----+
|letter| list_of_numbers|ones|
+------+----------------+----+
|     A|    [3, 1, 2, 3]|   1|
|     B|    [1, 2, 1, 1]|   3|
+------+----------------+----+
Run Code Online (Sandbox Code Playgroud)

到目前为止,我已经尝试过创建udf并且它完美地工作,但我想知道我是否可以在不定义任何udf.

pau*_*ult 7

您可以分解数组并过滤 的分解值1。然后groupBy和count:

from pyspark.sql.functions import col, count, explode

df.select("*", explode("list_of_numbers").alias("exploded"))\
    .where(col("exploded") == 1)\
    .groupBy("letter", "list_of_numbers")\
    .agg(count("exploded").alias("ones"))\
    .show()
#+------+---------------+----+
#|letter|list_of_numbers|ones|
#+------+---------------+----+
#|     A|   [3, 1, 2, 3]|   1|
#|     B|   [1, 2, 1, 1]|   3|
#+------+---------------+----+
Run Code Online (Sandbox Code Playgroud)

为了保留所有行,即使计数为 0,您也可以将exploded列转换为指示变量。然后groupBy和sum。

from pyspark.sql.functions import col, count, explode, sum as sum_

df.select("*", explode("list_of_numbers").alias("exploded"))\
    .withColumn("exploded", (col("exploded") == 1).cast("int"))\
    .groupBy("letter", "list_of_numbers")\
    .agg(sum_("exploded").alias("ones"))\
    .show()
Run Code Online (Sandbox Code Playgroud)

请注意,我已导入pyspark.sql.functions.sum为sum_不覆盖内置sum函数。


小智 5

从 pyspark 3+ 开始,我们可以使用数组转换。

https://mungingdata.com/spark-3/array-exists-forall-transform-aggregate-zip_with/ https://medium.com/expedia-group-tech/deep-dive-into-apache-spark-array-函数-720b8fbfa729

import pyspark.sql.functions as F

df = spark_session.createDataFrame(
    [
        ['A',[3, 1, 2, 3]],
        ['B',[1, 2, 1, 1]]
    ],      
        ['letter','list_of_numbers'])

df1 = df.selectExpr('*','filter(list_of_numbers, x->x=1) as ones_array')
df2 = df1.selectExpr('*', 'size(ones_array) as ones')
df2.show()

+------+---------------+----------+----+
|letter|list_of_numbers|ones_array|ones|
+------+---------------+----------+----+
|     A|   [3, 1, 2, 3]|       [1]|   1|
|     B|   [1, 2, 1, 1]| [1, 1, 1]|   3|
+------+---------------+----------+----+
Run Code Online (Sandbox Code Playgroud)