17

我正在寻找accumarraynumpy 中 MATLAB 的快速解决方案。accumarray累加数组中属于同一索引的元素。一个例子:

a = np.arange(1,11)
# array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])
accmap = np.array([0,1,0,0,0,1,1,2,2,1])

结果应该是

array([13, 25, 17])

到目前为止我所做的: 我已经尝试过这里的配方accum中的功能,它工作正常但速度很慢。

accmap = np.repeat(np.arange(1000), 20)
a = np.random.randn(accmap.size)
%timeit accum(accmap, a, np.sum)
# 1 loops, best of 3: 293 ms per loop

然后我尝试使用这里的解决方案,它应该工作得更快,但它不能正常工作:

accum_np(accmap, a)
# array([  1.,   2.,  12.,  13.,  17.,  10.])

是否有一个内置的 numpy 函数可以像这样进行累积?或者有什么其他推荐吗?

4

7 回答 7

21

np.bincountweights可选参数一起使用。在您的示例中,您将执行以下操作:

np.bincount(accmap, weights=a)
于 2013-05-31T12:53:54.797 回答
8

派对迟到了,但是...

正如@Jamie 所说,对于求和的情况,np.bincount快速而简单。但是,在更一般的情况下,对于其他ufuncs诸如maximum,您可以使用该np.ufunc.at方法。

我整理了一个要点[请参见下面的链接],它将其封装在一个类似 Matlab 的界面中。它还利用重复的索引规则来提供一个'last'and'first'函数,并且与 Matlab 不同的'mean'是,它进行了明智的优化(在 Matlab 中调用accumarraywith@mean真的很慢,因为它为每个单独的组运行一个非内置函数,这很愚蠢)。

请注意,我没有特别测试要点,但希望将来会通过额外的功能和错误修复对其进行更新。

2015 年 5 月/6 月更新:我已经重新设计了我的实现 - 它现在作为ml31415/numpy-groupies的一部分提供,并且可以在 PyPi ( pip install numpy-groupies) 上使用。基准如下(有关最新值,请参阅 github repo)...

function  pure-py  np-grouploop   np-ufuncat np-optimised    pandas        ratio
     std  1737.8ms       171.8ms     no-impl       7.0ms    no-impl   247.1: 24.4:  -  : 1.0 :  -  
     all  1280.8ms        62.2ms      41.8ms       6.6ms    550.7ms   193.5: 9.4 : 6.3 : 1.0 : 83.2
     min  1358.7ms        59.6ms      42.6ms      42.7ms     24.5ms    55.4: 2.4 : 1.7 : 1.7 : 1.0 
     max  1538.3ms        55.9ms      38.8ms      37.5ms     18.8ms    81.9: 3.0 : 2.1 : 2.0 : 1.0 
     sum  1532.8ms        62.6ms      40.6ms       1.9ms     20.4ms   808.5: 33.0: 21.4: 1.0 : 10.7
     var  1756.8ms       146.2ms     no-impl       6.3ms    no-impl   279.1: 23.2:  -  : 1.0 :  -  
    prod  1448.8ms        55.2ms      39.9ms      38.7ms     20.2ms    71.7: 2.7 : 2.0 : 1.9 : 1.0 
     any  1399.5ms        69.1ms      41.1ms       5.7ms    558.8ms   246.2: 12.2: 7.2 : 1.0 : 98.3
    mean  1321.3ms        88.3ms     no-impl       4.0ms     20.9ms   327.6: 21.9:  -  : 1.0 : 5.2 
Python 2.7.9, Numpy 1.9.2, Win7 Core i7.

在这里,我们使用从 中100,000统一挑选的索引[0, 1000)。具体来说,大约 25% 的值是0(用于布尔运算),其余的均匀分布在[-50,25). 时间显示为 10 次重复。

  • purepy - 只使用纯 python,部分依赖itertools.groupby.
  • np-grouploop - 用于numpy根据 对值进行排序idx,然后用于split创建单独的数组,然后遍历这些数组,numpy为每个数组运行相关函数。
  • np-ufuncat - 使用该numpy ufunc.at方法,该方法比应有的速度慢 - 正如我在 numpy 的 github repo 上创建的问题中失败的那样。
  • np-optimisied - 使用自定义numpy索引/其他技巧来击败上述两个实现(除了min max prod依赖之外ufunc.at)。
  • 熊猫-pd.DataFrame({'idx':idx, 'vals':vals}).groupby('idx').sum()等等。

请注意,有些no-impls 可能没有根据,但我还没有费心让它们工作。

正如 github 上所解释的,accumarray现在支持nan-prefixed 函数(例如nansum)以及 、sortrsortarray. 它也适用于多维索引。

于 2015-02-10T20:18:38.653 回答
4

我已经编写了一个 accumarray 实现scipy.weave并将其上传到 github:https ://github.com/ml31415/numpy-groupies

于 2013-05-31T19:24:13.937 回答
2

您可以在一行中使用 pandas DataFrame 执行此操作。

In [159]: df = pd.DataFrame({"y":np.arange(1,11),"x":[0,1,0,0,0,1,1,2,2,1]})

In [160]: df
Out[160]: 
   x   y
0  0   1
1  1   2
2  0   3
3  0   4
4  0   5
5  1   6
6  1   7
7  2   8
8  2   9
9  1  10

In [161]: pd.pivot_table(df,values='y',index='x',aggfunc=sum)
Out[161]: 
    y
x    
0  13
1  25
2  17

您可以告诉pivot_table使用特定列作为索引和值,并获取一个新的 DataFrame 对象。当您将聚合函数指定为 sum 时,结果将与 Matlab 的 accumarray 相同。

于 2018-05-08T12:02:58.640 回答
1

不如公认的答案好,但是:

[np.sum([a[x] for x in y]) for y in [list(np.where(accmap==z)) for z in np.unique(accmap).tolist()]]

这需要108us per loop(100000 个循环,最好的 3 个)

接受的答案 ( np.bincount(accmap, weights=a) 需要2.05us per loop(100000 循环,最好的 3)

于 2013-05-31T13:49:49.603 回答
0

以下情况如何:

import numpy

def accumarray(a, accmap):

    ordered_indices = numpy.argsort(accmap)

    ordered_accmap = accmap[ordered_indices]

    _, sum_indices = numpy.unique(ordered_accmap, return_index=True)

    cumulative_sum = numpy.cumsum(a[ordered_indices])[sum_indices-1]

    result = numpy.empty(len(sum_indices), dtype=a.dtype)
    result[:-1] = cumulative_sum[1:]
    result[-1] = cumulative_sum[0]

    result[1:] = result[1:] - cumulative_sum[1:]

    return result
于 2013-05-31T13:13:33.587 回答
0

这取决于您到底要做什么,但是 numpy unique 有一堆可选的输出,您可以使用它们来累积。如果您的数组有多个相同的值,则 unique 将通过将 return_counts 选项设置为 true 来计算有多少相同的值。在一些简单的应用程序中,这就是您需要做的所有事情。

numpy.unique(ar, return_index=False, return_inverse=False, return_counts=True, axis=None)

您还可以将索引设置为 true 并使用它来累积不同的数组。

于 2018-07-18T22:16:56.950 回答