如何根据 PySpark 数据框所有成对列的值制作混淆矩阵?

How to make a confusion matrix based on values from all the pairs of columns of a PySpark dataframe?

我有一个 PySpark 数据框

simpleData = [("person0",1, 1, 0), \
    ("person1",1, 1, 1), \
    ("person2",1, 0, 0), \
    ("person3",0 ,0, 0 ), \
  ]
columns= ['persons_name','A', 'B', 'C']
exp = spark.createDataFrame(data = simpleData, schema = columns)

exp.show()

它只包含二进制值(0 和 1) 这看起来像-

+------------+---+---+---+
|persons_name|  A|  B|  C|
+------------+---+---+---+
|     person0|  1|  1|  0|
|     person1|  1|  1|  1|
|     person2|  1|  0|  0|
|     person3|  0|  0|  0|
+------------+---+---+---+

我们需要用零初始化混淆矩阵,例如,

+---+---+---+---+
|   |  A|  B|  C|
+---+---+---+---+
|  A|  0|  0|  0|
|  B|  0|  0|  0|
|  C|  0|  0|  0|
+---+---+---+---+

现在我想用以下方式填充混淆矩阵- 对于数据框中的每一行 exp,我想为数据框中所有值 = 1 的列对增加混淆矩阵的计数器。

例如,对于 person0,只有 1 对列 A 和 B,其值 = 1。因此我们增加混淆矩阵的值在 ( A、B)和(B、A)。 这看起来像-

+---+---+---+---+
|   |  A|  B|  C|
+---+---+---+---+
|  A|  0|  1|  0|
|  B|  1|  0|  0|
|  C|  0|  0|  0|
+---+---+---+---+

对于 person1,有 3 对列,(A, B)、(A, C) 和 (B, C),它们的值为 1。所以我们在 (A, B)、(B, A)、(A, C)、(C, A)、(B, C) 和 (C, B) 处增加混淆矩阵的值。

现在更新后的混淆矩阵看起来像-

+---+---+---+---+
|   |  A|  B|  C|
+---+---+---+---+
|  A|  0|  2|  1|
|  B|  2|  0|  1|
|  C|  1|  1|  0|
+---+---+---+---+

person2person3 没有这样的对。所以我们不更新混淆矩阵。 最终的混淆矩阵看起来像-

+---+---+---+---+
|   |  A|  B|  C|
+---+---+---+---+
|  A|  0|  2|  1|
|  B|  2|  0|  1|
|  C|  1|  1|  0|
+---+---+---+---+

PySpark 如何实现?

假设您的原始数据框是一个包含列 A, B, C 的矩阵,可以通过将原始矩阵与其自身的转置相乘来计算混淆矩阵。换句话说,AB 的条目只是 A 列和 B 的点积,除了对角线 ,因此您基本上可以在列上进行嵌套循环,计算每对列的点积。

此外,一般情况下,列数应该足够小以便在本地主机上易于管理,您可以将结果收集到二维列表或 numpy 数组中:

import numpy as np
import pyspark.sql.functions as f

cols = ['A', 'B', 'C']
res = np.array([
  [exp.agg(f.sum(f.col(x) * f.col(y))).first()[0] if x != y else 0 for y in cols] 
  for x in cols
])

res
#[[0 2 1]
# [2 0 1]
# [1 1 0]]