numpy group by,返回按结果排序的原始索引

mgdq6dx1  于 2023-10-19  发布在  其他
关注(0)|答案(3)|浏览(117)

我有这样的数组:

array([[2, 1],
       [3, 5],
       [2, 1],
       [4, 2],
       [2, 3],
       [5, 3]])

我想做的是'group-by'按第一列求和,然后按第二列排序:

array([[2, 5],
       [3, 5],
       [5, 3],
       [4, 2]])

这里有一个转折,我还想从结果数组中的每一行的原始数组中获取索引,排序:

2       3     5    4
 [[0,2,4],  [1],  [5], [3] ]

如果它很容易…我需要得到前N个索引.假设top 2:

2       3    
  [0,2,4,    1]

没有Pandas,只有纯粹的numpy。
顺便说一句,我只需要前N个项目和他们的索引。这可以简化加速该过程
试着应用这些
https://izziswift.com/is-there-any-numpy-group-by-function

e37o9pze

e37o9pze1#

遗憾的是,Numpy中没有group by,但您可以使用np.unique来查找唯一元素及其索引,这足以实现您所需要的内容。一旦确定了键,就可以使用np.add.at执行基于键的归约。对于sort by值,可以使用np.argsort。有关详细信息,请参阅this postthis one

keys, index = np.unique(df[:,0], return_inverse=True) # Find the unique key to group
values = np.zeros(len(keys), dtype=np.int64)          # Sum-based accumulator
np.add.at(values, index, df[:,1])                     # Key-based accumulation
tmp = np.hstack([keys[:,None], values[:,None]])       # Build the key-sum 2D array
res = tmp[tmp[:, 1].argsort()[::-1]]                  # Sort by value

请注意,索引可以很容易地从index变量(这是一个反向索引)获得。没有办法用Numpy来构建它,但是可以使用一个简单的Python循环来积累索引i,这些索引存储在字典中的列表中,每个键keys[index[i]]。下面是一个示例:

from collections import defaultdict
d = defaultdict(list)
for i in range(len(df)): d[keys[index[i]]].append(i)
kx1ctssn

kx1ctssn2#

我对这个解决方案不满意,也无法验证它不会与其他数据中断。它使用了引用的思想来分组,但求和为add.reduceat

a = np.array(
      [[2, 1],
       [3, 5],
       [2, 1],
       [4, 2],
       [2, 3],
       [5, 3]])

s = a[:,0].argsort()
b = a[s]
groups, index = np.unique(b[:,0], return_index=True)
# splits = np.split(b[:,1], index[1:]) # if you need the groups
groupsum = np.stack([groups, np.add.reduceat(b[:,1], index)]).T
groupsum[(groupsum[:,1]*(-1)).argsort()]

输出

array([[2, 5],
       [3, 5],
       [5, 3],
       [4, 2]])

要获得每个组的索引,

np.stack([groups.astype(object),np.split(np.arange(len(a))[s], index[1:])]).T

输出

array([[2, array([0, 2, 4])],
       [3, array([1])],
       [4, array([3])],
       [5, array([5])]], dtype=object)
fdbelqdn

fdbelqdn3#

你可能会发现一个简单的通用group_by函数很有用,我发布了这个问题:https://stackoverflow.com/a/77150915/3671939
您可以使用它来解决这个问题,如下所示:

x = np.array([[2, 1], [3, 5], [2, 1], [4, 2], [2, 3], [5, 3]])
keys, idxs, sums = group_by(
    x[:, 0],
    lambda idx: x[idx[0], 0],
    lambda idx: [*idx],
    lambda idx: x[idx, 1].sum(),
)

N = 2
top = np.argsort(-sums)[:N]
print(keys[top]) # [2 3]
print([idxs[i] for i in top]) # [[0, 2, 4], [1]]

请注意,该函数是快速的,但不利用“只有N顶”的要求。这可以通过使用np.argpartition来完成,然后对较小的数组进行排序,尽管它可能不会产生任何显著的好处,因为group_by部分具有O(n log n)的复杂度和许多常量:

top = np.argpartition(sums, -N)[-N:]
top = top[np.argsort(-sums[top])]

相关问题