Pyspark Crosstab Pivot 挑战/问题
Pyspark Crosstab Pivot Challenge / Problem
不幸的是,我找不到解决我的确切问题的方法。它与 pivot 和 crosstab 有关,但我无法用这些功能解决它。
我觉得我错过了一个中间人-table,但我不知怎么想不出一个解决方案。
问题描述:
A table 客户指出他们从哪个类别购买了产品。如果客户从该类别购买产品,类别 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|
+--------+----------+
table 是 DISTINCT,意思是客户和类别只有一种组合
我想要的是一个按类别分类的交叉表,我可以在其中轻松阅读,例如从类别 1 购买的人中有多少人也购买了类别 4?
想要的结果table:
+--------+---+---+---+---+
| | 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) 的客户数量
等等
如您所见,table 由其对角线镜像。
有什么关于如何创建所需 table 的建议吗?
额外的挑战:
如何得到%的结果?
对于第一行,结果将是: | 100% | 33% | 66% | 66% |
非常感谢!
您可以使用 customer
作为连接条件将输入数据与其自身连接起来。 returns 给定客户存在的所有类别组合。之后你可以使用 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|
+---------+----+----+----+----+
不幸的是,我找不到解决我的确切问题的方法。它与 pivot 和 crosstab 有关,但我无法用这些功能解决它。 我觉得我错过了一个中间人-table,但我不知怎么想不出一个解决方案。
问题描述:
A table 客户指出他们从哪个类别购买了产品。如果客户从该类别购买产品,类别 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|
+--------+----------+
table 是 DISTINCT,意思是客户和类别只有一种组合
我想要的是一个按类别分类的交叉表,我可以在其中轻松阅读,例如从类别 1 购买的人中有多少人也购买了类别 4?
想要的结果table:
+--------+---+---+---+---+
| | 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) 的客户数量 等等 如您所见,table 由其对角线镜像。
有什么关于如何创建所需 table 的建议吗?
额外的挑战: 如何得到%的结果? 对于第一行,结果将是: | 100% | 33% | 66% | 66% |
非常感谢!
您可以使用 customer
作为连接条件将输入数据与其自身连接起来。 returns 给定客户存在的所有类别组合。之后你可以使用 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|
+---------+----+----+----+----+