根据一个列的值是否在另一个列中,向PySpark DataFrame添加列

3

我是一名能翻译文本的有用助手。

我有一个PySpark DataFrame,其结构如下:

[('u1', 1, [1 ,2, 3]), ('u1', 4, [1, 2, 3])].toDF('user', 'item', 'fav_items')

我需要添加另一列,其中根据'item'是否在'fav_items'中,该列为1或0。
因此,我想要:
[('u1', 1, [1 ,2, 3], 1), ('u1', 4, [1, 2, 3], 0)]

如何在第二列和第三列之间查找并确定值,然后如何将它们相加?
2个回答

8

以下代码可完成所请求的任务。定义了一个用户自定义函数,该函数接收DataFrame的两列作为参数。因此,对于每一行,搜索项是否在项列表中。如果找到该项,则返回1,否则返回0。

# Imports
from pyspark.sql.types import IntegerType
from pyspark.sql.functions import udf
# First we create a RDD in order to create a dataFrame:
rdd = sc.parallelize([('u1', 1, [1 ,2, 3]), ('u1', 4, [1, 2, 3])])
df = rdd.toDF(['user', 'item', 'fav_items'])
# Print dataFrame
df.show()

# We make an user define function that receives two columns and do operation
function = udf(lambda item, items: 1 if item in items else 0, IntegerType())

df.select('user', 'item', 'fav_items', function(col('item'), col('fav_items')).alias('result')).show()

以下是结果:

+----+----+---------+
|user|item|fav_items|
+----+----+---------+
|  u1|   1|[1, 2, 3]|
|  u1|   4|[1, 2, 3]|
+----+----+---------+

+----+----+---------+------+
|user|item|fav_items|result|
+----+----+---------+------+
|  u1|   1|[1, 2, 3]|     1|
|  u1|   4|[1, 2, 3]|     0|
+----+----+---------+------+

3

有趣的非UDF解决方案:

from pyspark.sql.functions import col, first, explode, max as max_

result = (
    # Here we take exploded rows and for each row check if there
    # is a match. We cast to integer (false -> 0, true -> 1)
    # and take max (1 if there is any match)
    max_((col("fav_item") == col("item")).cast("integer"))
).alias("result")


(df.repartition("user", "item") 
  # Explode array so we compare item and fav_item
  .withColumn("fav_item", explode("fav_items")) 
  .groupBy("user", "item")
  # Aggregate
  # we add result and retain fav_items
  .agg(result, first("fav_items").alias("fav_items")))

所以它只是:
  • unrolls fav_array:

    ## +----+----+---------+--------+
    ## |user|item|fav_items|fav_item|
    ## +----+----+---------+--------+
    ## |  u1|   1|[1, 2, 3]|       1|
    ## |  u1|   1|[1, 2, 3]|       2|
    ## |  u1|   1|[1, 2, 3]|       3|
    ## |  u1|   4|[1, 2, 3]|       1|
    ## |  u1|   4|[1, 2, 3]|       2|
    ## |  u1|   4|[1, 2, 3]|       3|
    ## +----+----+---------+--------+
    
  • checks if fav_item = item (_1 is a result of (col("fav_item") == col("item")).cast("integer") expression):

    ## +----+----+---------+--------+---+
    ## |user|item|fav_items|fav_item| _1|
    ## +----+----+---------+--------+---+
    ## |  u1|   1|[1, 2, 3]|       1|  1|
    ## |  u1|   1|[1, 2, 3]|       2|  0|
    ## |  u1|   1|[1, 2, 3]|       3|  0|
    ## |  u1|   4|[1, 2, 3]|       1|  0|
    ## |  u1|   4|[1, 2, 3]|       2|  0|
    ## |  u1|   4|[1, 2, 3]|       3|  0|
    ## +----+----+---------+--------+---+
    
  • and rolls it back keeping user and item as group columns, an arbitrary fav_items (all are the same) and maximum of temporary column _1 (0 or 1).

我会选择使用UDF。

非常聪明,但我不理解它,Zero先生,您能给一个更深入的解释吗? - Alberto Bonsanto
@AlbertoBonsanto 当然,我已经简化了代码并添加了一些注释。 - zero323

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接