创建一个计算关系记录的对称矩阵

Create a symmetric matrix that counts the relational records

我想通过基于另一列(ID)的一列(Value)计算所有可能的成对关系的数量。

示例数据框:

   ID Value
0   1     A
1   1     A
2   1     A
3   1     B
4   1     C
5   2     B
6   2     C
7   2     C

生成示例数据框:

import pandas as pd
df = pd.DataFrame({'ID'    : {0:  1,  1: 1,   2: 1,   3: 1,   4: 1,   
                              5:  2,  6: 2,   7: 2}, 
                   'Value' : {0: 'A', 1: 'A', 2: 'A', 3: 'B', 4: 'C',
                              5: 'B', 6: 'C', 7: 'C'} 
                   })

应该对 ID=1ID=2 进行成对计数。

可能的配对,其中 ID=1

(A,A), (A,A), (A,B), (A,C),
(A,A), (A,A), (A,B), (A,C),
(A,A), (A,A), (A,B), (A,C),
(B,A), (B,A), (B,A), (B,C),
(C,A), (C,A), (C,A), (C,B),

可能的配对,其中 ID=2

(B,C), (B,C)
(C,B), (C,C)
(C,B), (C,C)

预期数据帧:

   A  B  C
A  6  3  3
B  3  0  3
C  3  3  2

我目前得到的(见下面与其他 Whosebug 问题的关系):

df = pd.merge(df, df, on='ID')
df = pd.crosstab(df['Value_x'], df['Value_y']).rename_axis(None).rename_axis(None, axis=1)
print (df)

错误的输出:

   A  B  C
A  9  3  3
B  3  2  3
C  3  3  5

正如您可能发现的那样,这个问题主要与对角醛有关。我假设我必须专注于合并方面来处理提议的场景。但是,到目前为止我无法处理:(有什么建议吗? 提前致谢!

相关问题: 有各种相似之处。但是,该问题的期望值可能略有错误。 (A, A) = 0, (B,B) = 0, (C,C) = 0 的情况应为 0,因为根据该问题,它们在两种情况下(ID=1 或 ID=2)都不存在.如果我们只想计算那些条件 > AB、AC、BA、BC、CA、CB(来自 ID=1)和 BC、CB(来自 ID=2)。另一方面,这里的主要区别在于对角线。

您可以使用 itertool.permutations 但将其应用于每个组:

from itertools import permutations

out = pd.DataFrame()
for _, g in df.groupby("ID"):
    d = pd.DataFrame(permutations(g["Value"], 2), columns=["x", "y"])
    x = pd.crosstab(d["x"], d["y"]).rename_axis(None).rename_axis(None, axis=1)
    out = out.add(x, fill_value=0)

print(out.astype(int))

打印:

   A  B  C
A  6  3  3
B  3  0  3
C  3  3  2

如果您需要访问排列,您也可以在一个框架中构建所有排列,然后获取整个交叉表。

import pandas as pd
from itertools import permutations

df = pd.DataFrame({'ID': {0: 1, 1: 1, 2: 1, 3: 1, 4: 1,
                          5: 2, 6: 2, 7: 2},
                   'Value': {0: 'A', 1: 'A', 2: 'A', 3: 'B', 4: 'C',
                             5: 'B', 6: 'C', 7: 'C'}
                   })

perms = df.groupby('ID')['Value'] \
    .apply(lambda s: pd.DataFrame(permutations(s, 2), columns=['x', 'y']))

new_df = pd.crosstab(perms.x, perms.y) \
    .rename_axis(None, axis=1) \
    .rename_axis(None, axis=0)

# For Display
print(new_df)
print()
print(perms)

输出
new_df:

   A  B  C
A  6  3  3
B  3  0  3
C  3  3  2

烫发:

       x  y
ID         
1  0   A  A
   1   A  A
   2   A  B
   3   A  C
   4   A  A
   5   A  A
   6   A  B
   7   A  C
   8   A  A
   9   A  A
   10  A  B
   11  A  C
   12  B  A
   13  B  A
   14  B  A
   15  B  C
   16  C  A
   17  C  A
   18  C  A
   19  C  B
2  0   B  C
   1   B  C
   2   C  B
   3   C  C
   4   C  B
   5   C  C

让我们在crosstab之后尝试dot,然后减去自身对~

s = pd.crosstab(df.ID,df.Value)
out = s.T.dot(s)
np.fill_diagonal(out.values, out.values.diagonal() - s.sum())
out
Value  A  B  C
Value         
A      6  3  3
B      3  0  3
C      3  3  2