在Spark环境中混合使用python map和lambda函数时,我遇到了一个问题。
给出df1,我的源数据框:
Animals | Food | Home
----------------------------------
Monkey | Banana | Jungle
Dog | Meat | Garden
Cat | Fish | House
Elephant | Banana | Jungle
Lion | Meat | Desert
我想创建另一个数据框df2。它将包含两列,每列df1(在我的示例中为3)。 第一列将包含df1列的名称。第二列将包含出现次数最多的元素数组(在下面的示例中,n = 3)和计数。
Column | Content
-----------------------------------------------------------
Animals | [("Cat", 1), ("Dog", 1), ("Elephant", 1)]
Food | [("Banana", 2), ("Meat", 2), ("Fish", 1)]
Home | [("Jungle", 2), ("Desert", 1), ("Garden", 1)]
我尝试使用python list,map和lambda函数来实现,但与PySpark函数有冲突:
def transform(df1):
# Number of entry to keep per row
n = 3
# Add a column for the count of occurence
df1 = df1.withColumn("future_occurences", F.lit(1))
df2 = df1.withColumn("Content",
F.array(
F.create_map(
lambda x: (x,
[
str(row[x]) for row in df1.groupBy(x).agg(
F.sum("future_occurences").alias("occurences")
).orderBy(
F.desc("occurences")
).select(x).limit(n).collect()
]
), df1.columns
)
)
)
return df2
错误是:
TypeError: Invalid argument, not a string or column: <function <lambda> at 0x7fc844430410> of type <type 'function'>. For column literals, use 'lit', 'array', 'struct' or 'create_map' function.
有什么想法要解决吗?
非常感谢!
答案 0 :(得分:2)
这是一个可能的解决方案,其中Content
列将是StructType
的数组,其中包含两个命名字段:Content
和count
。
from pyspark.sql.functions import col, collect_list, desc, lit, struct
from functools import reduce
def transform(df, n):
return reduce(
lambda a, b: a.unionAll(b),
(
df.groupBy(c).count()\
.orderBy(desc("count"), c)\
.limit(n)\
.withColumn("Column", lit(c))\
.groupBy("Column")\
.agg(
collect_list(
struct(
col(c).cast("string").alias("Content"),
"count")
).alias("Content")
)
for c in df.columns
)
)
此函数将遍历输入DataFrame df
中的每一列,并计算每个值的出现。然后,我们orderBy
的计数(降序)及其自身的列值(按字母顺序)并仅保留前n
行(limit(n)
)。
接下来,将这些值收集到一个结构数组中,最后union
一起将每一列的结果组合在一起。由于union
要求每个DataFrame具有相同的架构,因此您需要将列值转换为字符串。
n = 3
df1 = transform(df, n)
df1.show(truncate=False)
#+-------+------------------------------------+
#|Column |Content |
#+-------+------------------------------------+
#|Animals|[[Cat,1], [Dog,1], [Elephant,1]] |
#|Food |[[Banana,2], [Meat,2], [Fish,1]] |
#|Home |[[Jungle,2], [Desert,1], [Garden,1]]|
#+-------+------------------------------------+
这与您要求的输出不完全相同,但可能足以满足您的需求。 (Spark没有您所描述的元组。)这是新的模式:
df1.printSchema()
#root
# |-- Column: string (nullable = false)
# |-- Content: array (nullable = true)
# | |-- element: struct (containsNull = true)
# | | |-- Content: string (nullable = true)
# | | |-- count: long (nullable = false)