Pyspark交叉表枢轴挑战/问题

Pyspark交叉表枢轴挑战/问题,pyspark,pivot,crosstab,Pyspark,Pivot,Crosstab,不幸的是,我找不到解决问题的办法。它与pivot和crosstab有关,但我无法用这些函数解决它。 我有种感觉,我错过了一张中间的桌子,但不知何故,我无法想出一个解决办法 问题描述: 有客户的表格,表明他们从哪个类别购买了产品。如果客户从该类别购买了产品,则类别ID将显示在其姓名旁边 有4个类别1-4和3个客户A、B、C +--------+----------+ |customer| category | +--------+----------+ | A| 1|

不幸的是,我找不到解决问题的办法。它与pivot和crosstab有关,但我无法用这些函数解决它。 我有种感觉,我错过了一张中间的桌子,但不知何故,我无法想出一个解决办法

问题描述:

有客户的表格,表明他们从哪个类别购买了产品。如果客户从该类别购买了产品,则类别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|
+--------+----------+
该表具有独特的含义,即只有一个custmer和category组合

我想要的是一个按类别划分的交叉表,我可以轻松阅读,例如,从类别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|
+--------+---+---+---+---+
阅读示例: 第1行第1列:购买产品1(A、B、C)的客户总数 第1行第2列:购买产品1和产品2的客户数量(A) 第1行第3列:购买产品1和产品3的客户数量(A、C) 等 如您所见,该表通过其对角线镜像

对如何创建所需的表有何建议

其他挑战: 如何将结果设置为%? 对于第一行,结果将为:| 100%| 33%| 66%| 66%|


非常感谢

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

df2=df.WithColumnRename(“类别”、“cat1”)。加入(df.WithColumnRename(“类别”、“cat2”)、“客户”)\
.交叉表(“第1类”、“第2类”)\
.订购人(“cat1\U cat2”)
df2.show()
输出:

+---------+---+---+---+---+
|一类|二类|一|二|三|四|
+---------+---+---+---+---+
|        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]表示df2.columns中的col,如果col!=“cat1\u cat2”))\
.选择(“cat1_cat2”、*(F.round(df2[col]/F.col(“sum”),2.如果col!=“cat1_cat2”),则为df2.columns中的col选择别名(col))\
.show()
输出:

+---------+----+----+----+----+
|一类|二类|一|二|三|四|
+---------+----+----+----+----+
|        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.withColumnRename('category'、'cat1_cat2')、'cat1_cat2'、'inner')cz3=df2.select(“cat1_cat2”、*(F.round(df2[col]/F.col(“total”),2)别名(col)对于df2.columns中的col,如果col!=“cat1\u cat2”)
Oh我忘了显示“df\u max”的来源:
df\u max=df.groupBy('category').agg(F.countDistinct('customer').alias('total')