【问题标题】:Pyspark Crosstab Pivot Challenge / ProblemPyspark Crosstab Pivot 挑战/问题
【发布时间】:2021-01-15 07:21:33
【问题描述】:

很遗憾,我无法为我的确切问题找到解决方案。它与数据透视表和交叉表有关,但我无法用这些函数解决它。 我感觉我错过了一个中间表,但我不知何故无法提出解决方案。

问题描述:

一张表格,其中包含客户,表明他们从哪个类别购买了产品。如果客户从该类别购买了产品,则类别 ID 将显示在他的姓名旁边。

有 4 个类别 1 - 4 和 3 个客户 A、B、C

+--------+----------+
|customer| category |
+--------+----------+
|       A|         1|
|       A|         2|
|       A|         3|
|       B|         1|
|       B|         4|
|       C|         1|
|       C|         3|
|       C|         4|
+--------+----------+

表格是 DISTINCT 表示只有一种客户和类别组合

我想要的是按类别划分的交叉表,我可以在其中轻松阅读,例如从第 1 类购买的人中有多少也从第 4 类购买?

所需结果表:

+--------+---+---+---+---+
|        | 1 | 2 | 3 | 4 |
+--------+---+---+---+---+
|       1|  3|  1|  2|  2|
|       2|  1|  1|  1|  0|
|       3|  2|  1|  2|  1|
|       4|  2|  0|  1|  1|
+--------+---+---+---+---+

阅读示例: row1 column1 : 购买产品 1 (A, B, C) 的客户总数 row1 column2 : 购买产品 1 和 2 (A) 的客户数量 row1 column3 : 购买产品 1 和 3 (A, C) 的客户数量 等等。 如您所见,该表由其对角线镜像。

对如何创建所需的表有任何建议吗?

额外挑战: 如何获得结果为%? 对于第一行,结果将是:| 100% | 33% | 66% | 66% |

非常感谢!

【问题讨论】:

    标签: pyspark pivot crosstab


    【解决方案1】:

    您可以使用customer 作为连接标准来连接输入数据。这将返回给定客户存在的所有类别组合。之后,您可以使用crosstab 获取结果。

    df2 = df.withColumnRenamed("category", "cat1").join(df.withColumnRenamed("category", "cat2"), "customer") \
      .crosstab("cat1", "cat2") \
      .orderBy("cat1_cat2") 
    df2.show()
    

    输出:

    +---------+---+---+---+---+
    |cat1_cat2|  1|  2|  3|  4|
    +---------+---+---+---+---+
    |        1|  3|  1|  2|  2|
    |        2|  1|  1|  1|  0|
    |        3|  2|  1|  2|  1|
    |        4|  2|  0|  1|  2|
    +---------+---+---+---+---+
    

    要获得相对频率,您可以对每一行求和,然后将每个元素除以该总和。

    df2.withColumn("sum", sum(df2[col] for col in df2.columns if col != "cat1_cat2")) \
      .select("cat1_cat2", *(F.round(df2[col]/F.col("sum"),2).alias(col) for col in df2.columns if col != "cat1_cat2")) \
      .show()
    

    输出:

    +---------+----+----+----+----+
    |cat1_cat2|   1|   2|   3|   4|
    +---------+----+----+----+----+
    |        1|0.38|0.13|0.25|0.25|
    |        2|0.33|0.33|0.33| 0.0|
    |        3|0.33|0.17|0.33|0.17|
    |        4| 0.4| 0.0| 0.2| 0.4|
    +---------+----+----+----+----+
    

    【讨论】:

    • 您好维尔纳,感谢您的帮助。第一个解决方案完美运行!需要修改的第二个作为基础 (100%) 始终是对角线 (1-1; 2-2 等)。因此,我通过以下方式修改了您的解决方案:计算每个类别的不同客户并将其加入交叉表并使用它而不是行的总和:df2 = df2.join(df_max.withColumnRenamed('category', 'cat1_cat2'), 'cat1_cat2', 'inner') cz3 = df2.select("cat1_cat2", *(F.round(df2[col]/F.col("total"),2).alias(col) for col in df2.columns if col != "cat1_cat2"))
    • 哦,我忘了显示“df_max”的来源:df_max = df.groupBy('category').agg(F.countDistinct('customer').alias('total'))
    猜你喜欢
    • 2010-12-22
    • 1970-01-01
    • 2021-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-02
    • 2021-11-06
    • 1970-01-01
    相关资源
    最近更新 更多