ArrayColumn Pyspark 上的计数器函数

Car*_*llo 3 counter apache-spark apache-spark-sql pyspark

从这个数据框

+-----+-----------------+
|store|     values      |
+-----+-----------------+
|    1|[1, 2, 3,4, 5, 6]|
|    2|            [2,3]|
+-----+-----------------+
Run Code Online (Sandbox Code Playgroud)

我想应用这个Counter函数来得到这个:

+-----+------------------------------+
|store|     values                   |
+-----+------------------------------+
|    1|{1:1, 2:1, 3:1, 4:1, 5:1, 6:1}|
|    2|{2:1, 3:1}                    |
+-----+------------------------------+
Run Code Online (Sandbox Code Playgroud)

我使用另一个问题的答案得到了这个数据框:

GroupBy 和 concat 数组列 pyspark

所以我尝试修改答案中的代码,如下所示:

选项1:

+-----+-----------------+
|store|     values      |
+-----+-----------------+
|    1|[1, 2, 3,4, 5, 6]|
|    2|            [2,3]|
+-----+-----------------+
Run Code Online (Sandbox Code Playgroud)

选项 2:

+-----+------------------------------+
|store|     values                   |
+-----+------------------------------+
|    1|{1:1, 2:1, 3:1, 4:1, 5:1, 6:1}|
|    2|{2:1, 3:1}                    |
+-----+------------------------------+
Run Code Online (Sandbox Code Playgroud)

但它不起作用。

有谁知道我该怎么做?

谢谢

hi-*_*zir 8

您只需要提供正确的数据类型

udf_flatten_counter = sf.udf(
    lambda x: dict(Counter(x)),
    ty.MapType(ty.IntegerType(), ty.IntegerType()))

df = spark.createDataFrame(
   [(1, [1, 2, 3, 4, 5, 6]), (2, [2, 3])], ("store", "values"))


df.withColumn("cnt", udf_flatten_counter("values")).show(2, False)
# +-----+------------------+---------------------------------------------------+
# |store|values            |cnt                                                |
# +-----+------------------+---------------------------------------------------+
# |1    |[1, 2, 3, 4, 5, 6]|Map(5 -> 1, 1 -> 1, 6 -> 1, 2 -> 1, 3 -> 1, 4 -> 1)|
# |2    |[2, 3]            |Map(2 -> 1, 3 -> 1)                                |
# +-----+------------------+---------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

与 RDD 类似

df.rdd.mapValues(Counter).mapValues(dict).toDF(["store", "values"]).show(2, False)
# +-----+---------------------------------------------------+
# |store|values                                             |
# +-----+---------------------------------------------------+
# |1    |Map(5 -> 1, 1 -> 1, 6 -> 1, 2 -> 1, 3 -> 1, 4 -> 1)|
# |2    |Map(2 -> 1, 3 -> 1)                                |
# +-----+---------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

转换为dict是必要的,因为显然 Pyrolite 不能处理Counter对象。