Pyspark-将具有最大值的列转换为单独的1和0条目



我在pandas中有一个解决这个问题的工作版本,但我很难将它翻译成pyspark。

我的输入数据帧如下所示:

test_df = pd.DataFrame({
'id': [1],
'cat_1': [2],
'cat_2': [2],
'cat_3': [1]
})
test_df_spark = spark.createDataFrame(test_df)
test_df_spark.show()
+---+-----+-----+-----+
| id|cat_1|cat_2|cat_3|
+---+-----+-----+-----+
|  1|    2|    2|    1| <- non-maximum
+---+-----+-----+-----+
^     ^
|     |
maximum maximum    

我想:

  1. 获取cat_1、cat_2、cat_3中具有最大值的列(1个或多个(。在本例中,它们将是cat_1和cat_2
  2. 这些列的值应该为1。其余非最大列将设置为0
  3. 值为1的列应划分为单独的行

生成的数据帧应该如下所示:

+---+-----+-----+-----+
| id|cat_1|cat_2|cat_3|
+---+-----+-----+-----+
|  1|    1|    0|    0|
|  1|    0|    1|    0|
+---+-----+-----+-----+

目前,我最多能想到的是如何根据列的值(无论是否为最大值(将列设置为1或0,但我仍然不知道如何生成其他条目:

columns = ['cat_1', 'cat_2', 'cat_3']
(
test_df_spark
.withColumn(
'max_value',
F.greatest(
*columns
)
)
.select(
'id',
*[F.when(F.col(c) == F.col('max_value'), F.lit(1)).otherwise(F.lit(0)).alias(c) for c in columns]
)
.show()
)
+---+-----+-----+-----+
| id|cat_1|cat_2|cat_3|
+---+-----+-----+-----+
|  1|    1|    1|    0|
+---+-----+-----+-----+

提前感谢!

假设您当前的结果是df1:

columns = ['cat_1', 'cat_2', 'cat_3']
df1 = (
test_df_spark
.withColumn(
'max_value',
F.greatest(
*columns
)
)
.select(
'id',
*[F.when(F.col(c) == F.col('max_value'), F.lit(1)).otherwise(F.lit(0)).alias(c) for c in columns]
)
)

您可以通过创建一个结构数组和inlineit:来操作df1以获得您想要的结果

df2 = df1.select(
'id', 
F.array(*[
F.when(
F.col(c1) == 1, 
F.struct(*[
F.lit(1).alias(c2) if i1 == i2 else F.lit(0).alias(c2) 
for i2, c2 in enumerate(columns)
])
) 
for i1, c1 in enumerate(columns)
]).alias('cat')
).selectExpr(
'id', 
'inline(filter(cat, x -> x is not null))'
)
df2.show()
+---+-----+-----+-----+
| id|cat_1|cat_2|cat_3|
+---+-----+-----+-----+
|  1|    1|    0|    0|
|  1|    0|    1|    0|
+---+-----+-----+-----+

最新更新