假设我在Python3.x中具有以下pandas DataFrame
import pandas as pd
dict1 = {'name':['dog', 'dog', 'cat', 'cat', 'cat', 'bird', 'bird', 'bird', 'bird'], 'number':[42, 42, 42, 42, 42, 42, 42, 42, 42], 'count':[1, 2, 4, 5, 7, 1, 2, 5, 8]}
df = pd.DataFrame(dict1)
print(df)
## name number count
## 0 dog 42 1
## 1 dog 42 2
## 2 cat 42 4
## 3 cat 42 5
## 4 cat 42 7
## 5 bird 42 1
## 6 bird 42 2
## 7 bird 42 5
## 8 bird 42 8
列counts
包含1到8的整数。我的目标是给定列name
中的唯一类别,使用每个组合“对”的计数填充一个8 x 8的零矩阵。
因此,dog
,cat
和bird
的组合对为:
dog: (1, 2)
cat: (4, 5), (4, 7), (5, 7)
bird: (1, 2), (1, 5), (1, 8), (2, 5), (2, 8), (5, 8)
对于每对,我将+1
添加到零矩阵中的相应条目。
此矩阵将是对称的,即(n, m) = (m, n)
。给定df
的矩阵将是:
1 2 3 4 5 6 7 8
1: 0 2 0 0 1 0 0 1
2: 2 0 0 0 1 0 0 1
3: 0 0 0 0 0 0 0 0
4: 0 0 0 0 1 0 1 0
5: 1 1 0 1 0 0 1 1
6: 0 0 0 0 0 0 0 0
7: 0 0 0 1 1 0 0 0
8: 1 1 0 0 1 0 0 0
请注意,(1,2)=(2,1)
的计数为2,来自dog
组合和bird
组合。
(1)为此,我认为最好在给定熊猫DataFrame的情况下创建一个“组合元组”列表。
也就是说,类似
list_combos = [(1, 2), (2, 1), (4, 5), (4, 7), (5, 7), (5, 4), (7, 4), (7, 5),
(1, 2), (1, 5), (1, 8), (2, 5), (2, 8), (5, 8), (2, 1), (5, 1),
(8, 1), (5, 2), (8, 2), (8, 5)]
鉴于矩阵是对称的,也许最好使用:
list_combos2 = [(1, 2), (4, 5), (4, 7), (5, 7), (1, 2), (1, 5), (1, 8), (2, 5), (2, 8), (5, 8)]
给定“名称”中的分类值,如何计算熊猫DataFrame中整体的排列?
(2)给定元组列表,填充该矩阵的算法上最有效的方法(即RAM)是什么?
我应该能够将一个元组列表输入到一个numpy数组中,但是一个如何填充零呢?
答案 0 :(得分:5)
您可以使用groupby,遍历组合并像这样构建矩阵:
import numpy as np
from itertools import combinations
mat = np.zeros((df['count'].max(), ) * 2)
idx = []
for _, g in df.groupby('name'):
idx.extend(combinations(g['count'] - 1, r=2))
np.add.at(mat, list(zip(*idx)), 1)
mat += mat.T
array([[0., 2., 0., 0., 1., 0., 0., 1.],
[2., 0., 0., 0., 1., 0., 0., 1.],
[0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0., 1., 0.],
[1., 1., 0., 1., 0., 0., 1., 1.],
[0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 1., 0., 0., 0.],
[1., 1., 0., 0., 1., 0., 0., 0.]])
也许 是一个更快的解决方案,但这是我能想到的最干净的解决方案。
答案 1 :(得分:3)
使用Numpy的bincount
from itertools import combinations, chain
from collections import defaultdict
d = defaultdict(list)
for tup in df.itertuples():
d[tup.name].append(tup.count)
i, j = zip(*chain(*(combinations(v, 2) for v in d.values())))
i, j = np.array(i + j) - 1, np.array(j + i) - 1
np.bincount(i * 8 + j, minlength=64).reshape(8, 8)
array([[0, 2, 0, 0, 1, 0, 0, 1],
[2, 0, 0, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 0],
[1, 1, 0, 1, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 0, 0],
[1, 1, 0, 0, 1, 0, 0, 0]])