【问题标题】:Sum matrix elements group by indices in Python在Python中按索引对矩阵元素进行求和
【发布时间】:2023-03-03 02:48:01
【问题描述】:

我有两个矩阵(相同的行和列):一个带有浮点值,它们按另一个矩阵中的索引分组。因此,我想要一个字典或列表,其中包含每个索引的元素总和。 索引始终从 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 单元格的矩阵,这个算法需要大约 28 毫秒才能完成。

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。

【问题讨论】:

  • 8 毫秒?我会说这非常快。您在寻找多快?
  • @Bayko 我正在寻找类似 ms 的东西。因为这个过程是在一个 ~6000*100 循环中。
  • 您可能正在寻找某种形式的 bincount。

标签: python numpy matrix sum indices


【解决方案1】:

您可以在此处使用 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 在更大的样本上应该更快)

【讨论】:

  • 这工作正常,但如果我的 a 元素是 float64?
  • @Mortafix 你能发布一个你如何创建矩阵的例子吗?
  • @user348302 我正在使用 K-Means 神经网络,所以我没有索引矩阵的生成器。
  • 你确定你以正确的顺序传递参数吗?索引是b,值是a?我将发布一个与您的输入名称匹配的函数
  • 是的,当然,我以正确的顺序传递参数.. 问题(在 Python Doc 中的 bincount 下已知)是 float64
【解决方案2】:

numpy_indexed 包对这个问题有高效简单的解决方案(免责声明:我是它的作者):

import numpy_indexed as npi
keys, values = npi.group_by(B.flatten()).sum(A.flatten())

【讨论】:

  • 如何在 Jupyter Notebook 中使用它?
  • 有一个 conda-forge 包和一个 pip 安装程序可用;笔记本与否应该没有区别。
【解决方案3】:

以下解决方案依赖于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)))

但如果您提前知道所有索引的列表,那么在这里硬编码会更有效。

【讨论】:

  • 如何将它与 float64 一起使用?
  • 你可以在A数组中拥有任何你想要的东西;是你要的吗?
  • 没关系,它适用于 float64。它比我的快(~10ms),但如果可能的话,我正在寻找一个更快的
猜你喜欢
  • 2017-05-24
  • 2019-05-13
  • 2018-10-13
  • 2019-08-24
  • 2017-09-30
  • 1970-01-01
  • 2018-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多