和矩阵元素按索引在Python中分组

时间:2018-07-10 14:54:02

标签: python numpy matrix sum indices

我有两个矩阵(相同的行和列):一个具有浮点值,它们由另一个矩阵中的索引分组。结果,我想要一个包含每个索引元素之和的字典或列表。 索引始终从0开始。

A = np.array([[0.52,0.25,-0.45,0.13],[-0.14,-0.41,0.31,-0.41]])
B = np.array([[1,3,1,2],[3,0,2,2]])

RESULT = {0: -0.41, 1: 0.07, 2: 0.03, 3: 0.11}

我找到了这个解决方案,但我正在寻找更快的解决方案。 我正在处理具有784 x 300单元的矩阵,该算法需要约28ms才能完成。

import numpy as np

def matrix_sum_by_indices(indices,matrix):
    a = np.hstack(indices)
    b = np.hstack(matrix)
    sidx = a.argsort()
    split_idx = np.flatnonzero(np.diff(a[sidx])>0)+1
    out = np.split(b[sidx], split_idx)
    return [sum(x) for x in out]

如果您能帮助我找到一个更好而又简单的解决方案,我将不胜感激!

编辑:我犯了一个错误,在300 * 10矩阵中,完成时间为〜8ms,而在784x300中为〜28ms。

EDIT2:我的A元素是float64,所以bincount给我ValueError。

3 个答案:

答案 0 :(得分:3)

您可以在此处使用 bincount

a = np.array([[0.52,0.25,-0.45,0.13],[-0.14,-0.41,0.31,-0.41]])
b = np.array([[1,3,1,2],[3,0,2,2]])

N = b.max() + 1
id = b + (N*np.arange(b.shape[0]))[:, None] # since you can't apply bincount to a 2D array
np.sum(np.bincount(id.ravel(), a.ravel()).reshape(a.shape[0], -1), axis=0)

输出:

array([-0.41,  0.07,  0.03,  0.11])

功能:

def using_bincount(indices, matrx):
    N = indices.max() + 1
    id = indices + (N*np.arange(indices.shape[0]))[:, None] # since you can't apply bincount to a 2D array
    return np.sum(np.bincount(id.ravel(), matrx.ravel()).reshape(matrx.shape[0], -1), axis=0)

此示例的时间:

In [5]: %timeit using_bincount(b, a)
31.1 µs ± 1.74 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [6]: %timeit matrix_sum_by_indices(b, a)
61.3 µs ± 2.62 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [88]: %timeit scipy.ndimage.sum(a, b, index=[0,1,2,3])
54 µs ± 218 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

scipy.ndimage.sum 在大得多的样本上应该更快)

答案 1 :(得分:1)

numpy_indexed软件包针对此问题提供了有效且简单的解决方案(免责声明:我是其作者):

version: "3.4"

services:
  A:        
    build: .
    volumes:
      - C:/usr/src/C
    depends_on:
      - C


  B:
    build: .
    volumes:
      - C:/usr/src/C

    depends_on:
      - C

  C:
    image: repository.com/C:1.0.0
    volumes:
      - C:/shared_code

volumes:
     C:

答案 2 :(得分:1)

以下基于scipy.ndimage.sum的解决方案针对速度进行了高度优化:

import numpy as np
A = np.array([[0.52,0.25,-0.45,0.13], [-0.14,-0.41,0.31,-0.41]])
B = np.array([[1,3,1,2], [3,0,2,2]])
import scipy.ndimage
print(scipy.ndimage.sum(A, B, index=[0,1,2,3]))

您可能需要花点时间才能使index参数正是您想要的参数。这是您要获得结果的索引列表。也许以下是一个很好的起点:

print(scipy.ndimage.sum(A,B, index=np.unique(B)))

但是,如果您提前知道所有索引的列表,则在此处对其进行硬编码会更有效。