确定每个产品对的联合会议数

时间:2019-05-21 22:12:44

标签: pyspark

我有这个数据框:

from pyspark.mllib.linalg.distributed import IndexedRow

rows = sc.parallelize([[1, "A"], [1, 'B'] , [1, "A"], [2, 'A'], [2, 'C'] ,[3,'A'], [3, 'B']])

rows_df = rows.toDF(["session_id", "product"])

rows_df.show()

+----------+-------+
|session_id|product|
+----------+-------+
|         1|      A|
|         1|      B|
|         1|      A|
|         2|      A|
|         2|      C|
|         3|      A|
|         3|      B|
+----------+-------+

我想知道每个产品对一起举行了多少次联合会议。同一产品可以在一个会话中多次出现,但是我只希望每个产品对每个会话一次计数。

样本输出:

+---------+---------+-----------------+
|product_a|product_b|num_join_sessions|
+---------+---------+-----------------+
|        A|        B|                2|
|        A|        C|                1|
|        B|        A|                2|
|        B|        C|                0|
|        C|        A|                1|
|        C|        B|                0|
+---------+---------+-----------------+

我不知道如何在pyspark中实现它。

2 个答案:

答案 0 :(得分:1)

获取具有联合会话对的联合会话计数非常容易。您可以通过在session_id上将DataFrame与其自身连接并过滤掉product相同的行来实现此目的。

然后,您按product对分组并计算不同的session_id

import pyspark.sql.functions as f

rows_df.alias("l").join(rows_df.alias("r"), on="session_id", how="inner")\
    .where("l.product != r.product")\
    .groupBy(f.col("l.product").alias("product_a"), f.col("r.product").alias("product_b"))\
    .agg(f.countDistinct("session_id").alias("num_join_sessions"))\
    .show()
#+---------+---------+-----------------+
#|product_a|product_b|num_join_sessions|
#+---------+---------+-----------------+
#|        A|        C|                1|
#|        C|        A|                1|
#|        B|        A|                2|
#|        A|        B|                2|
#+---------+---------+-----------------+

(注意:如果只希望使用一对唯一的产品,请在!=函数中将<更改为where)。

棘手的是,您还希望没有联合会话的配对。可以完成 ,但是效率不高,因为您需要获得每个产品配对的笛卡尔积。

不过,这是一种方法:

从以上所述开始,将RIGHT加入不同产品对的笛卡尔乘积中。

rows_df.alias("l").join(rows_df.alias("r"), on="session_id", how="inner")\
    .where("l.product != r.product")\
    .groupBy(f.col("l.product").alias("product_a"), f.col("r.product").alias("product_b"))\
    .agg(f.countDistinct("session_id").alias("num_join_sessions"))\
    .join(
        rows_df.selectExpr("product AS product_a").distinct().crossJoin(
            rows_df.selectExpr("product AS product_b").distinct()
        ).where("product_a != product_b").alias("pairs"),
        on=["product_a", "product_b"],
        how="right"
    )\
    .fillna(0)\
    .sort("product_a", "product_b")\
    .show()
#+---------+---------+-----------------+
#|product_a|product_b|num_join_sessions|
#+---------+---------+-----------------+
#|        A|        B|                2|
#|        A|        C|                1|
#|        B|        A|                2|
#|        B|        C|                0|
#|        C|        A|                1|
#|        C|        B|                0|
#+---------+---------+-----------------+

注意:sort不是必需的,但我将其包括在内以匹配所需输出的顺序。

答案 1 :(得分:0)

我认为应该这样做:

import pyspark.sql.functions as F

joint_sessions = rows_df.withColumnRenamed(
    'product', 'product_a'
).join(
    rows_df.withColumnRenamed('product', 'product_b'),
    on='session_id',
    how='inner'
).filter(
    F.col('product_a') != F.col('product_b')
).groupBy(
    'product_a',
    'product_b'
).agg(
    F.countDistinct('session_id').alias('num_join_sessions')
).select(
    'product_a',
    'product_b',
    'num_join_sessions'
)

joint_sessions.show()