Ці ёсць MATLAB accumarray эквівалент у NumPy?

Я шукаю для хуткага рашэння accumarray </а> у NumPy. <�Код> 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])

What I've done so far: I've tried the accum function in the

recipe here which works fine but is slow.

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 функцыя, якая можа рабіць назапашвання, як гэта? Або любыя іншыя рэкамендацыі?

15
Мой блог пост oudated. Паспрабуйце версію GitHub. яна мае добра якая ахоплівае набор тэстаў.
дададзена аўтар Michael, крыніца
@Michael і я стварыў пакет пад назвай Numpy-прыхільніц які ўключае ў сябе функцыю accumarray тыпу пад назвай запаўняльнік . Глядзіце мой адказ ніжэй для атрымання падрабязнай інфармацыі.
дададзена аўтар dan-man, крыніца

7 адказы

Выкарыстоўвайце np.bincount з вагі неабавязковы аргумент. У вашым прыкладзе вы маглі б зрабіць:

np.bincount(accmap, weights=a)
17
дададзена
ха! гэта акуратны :)
дададзена аўтар Henry Gomersall, крыніца

Пазней да партыі, але ...

Як кажа @Jamie, у выпадку падсумоўвання, np.bincount вельмі хутка і проста. Аднак у больш агульным выпадку, для іншых ufuncs , такія як максімальны , вы можаце выкарыстоўваць np.ufunc.at метад.

Я злучыў сутнасцю [гл спасылку ніжэй замест], які Інкапсулюйце гэта ў Matlab-падобны інтэрфейс. Ён таксама выкарыстоўвае неаднаразовых правілы індэксацыі, каб забяспечыць «апошні» і «першы» функцыя, і ў адрозненне ад Matlab, «сярэдні» з'яўляецца разважліва аптымізавана (выклік accumarray з @mean у Matlab вельмі павольна, таму што ён працуе без убудаванай функцыі для кожнай асобнай групы, якая па-дурному).

Майце на ўвазе, што я асабліва не тэставаў сутнасць, але мы спадзяемся, абнавіць яго ў будучыні з дадатковымі магчымасцямі і выпраўленьні.

Update May/June-2015: I have reworked my implementation - it is now available as part of ml31415/numpy-groupies and available on PyPi (pip install numpy-groupies). Benchmarks are as follows (see github repo for up-to-date values)...

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.

Тут мы выкарыстоўваем 100000 індэксы раўнамерна выбіраюцца з [0, 1000) . У прыватнасці, каля 25% значэнняў з'яўляюцца 0 (для выкарыстання з BOOL аперацый), а астатнія раўнамерна distribuited на [- 50,25) . Затрымкі паказаны для 10 паўтораў.

  • purepy - uses nothing but pure python, relying partly on itertools.groupby.
  • np-grouploop - uses numpy to sort values based on idx, then uses split to create separate arrays, and then loops over these arrays, running the relevant numpy function for each array.
  • np-ufuncat - uses the numpy ufunc.at method, which is slower than it ought to be - as disuccsed in an issue I created on numpy's github repo.
  • np-optimisied - uses custom numpy indexing/other tricks to beat the above two implementations (except for min max prod which rely on ufunc.at).
  • pandas - pd.DataFrame({'idx':idx, 'vals':vals}).groupby('idx').sum() etc.

Звярніце ўвагу, што некаторыя з ані-осущ s можа быць неапраўданым, але я не папрацаваў, каб прымусіць іх працаваць яшчэ.

Як тлумачыцца на GitHub, accumarray зараз падтрымлівае нан -prefixed функцыі (напрыклад, nansum ), а таксама, сартаваць , rsort і масіў . Яна таксама працуе з шматмернай індэксацыяй.

5
дададзена
верагодна, лепш, каб апублікаваць паведамленне пра памылку на GitHub РЭПО (пры ўмове, мінімальны прыклад кода дапаможа)
дададзена аўтар dan-man, крыніца
Добрая праца, хлопцы. Я спрабую выкарыстоўваць працэдуру. На жаль, я canßt прайграць тыя ж вынікі, як MATLAB, а таксама з шматмерным масівам гэта складана зразумець, як гэта працуе. Ці можаце вы дапамагчы мне трохі?
дададзена аўтар Nikko, крыніца
Тнх для адказу. Я прымушу пытанне каму заклікаць Numpy прыхільніцы агрэгаваць
дададзена аўтар Nikko, крыніца

I've written an accumarray implementation with scipy.weave and uploaded it at github: https://github.com/ml31415/numpy-groupies

3
дададзена

Не так добра, як прынята адказваць, але:

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

Гэта займае 108us у цыкле (100000 цыклаў, лепш за ўсё з 3)

Прыняты адказ ( np.bincount (accmap, вага = а ) прымае 2.05us у цыкле (100000 цыклаў, лепш за ўсё з 3)

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
0
дададзена

Вы можаце зрабіць гэта з пандамі 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. Пры ўказанні функцыі агрэгацыі ў выглядзе сумы вынікі будуць ідэнтычныя accumarray ад Matlab.

0
дададзена

Гэта залежыць ад таго, што менавіта вы спрабуеце зрабіць, але NumPy унікальны мае кучу дадатковых выхадаў, якія можна выкарыстоўваць для назапашвання. Калі масіў мае некалькі аднолькавых значэнняў, то унікальны будзе падлічыць, колькі ідэнтычных значэнняў ёсць, усталяваўшы опцыю return_counts ў рэчаіснасць. У некаторых простых прыкладаннях, гэта ўсё, што вам трэба зрабіць.

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

Вы можаце таксама ўсталяваць індэкс для праўдзівыя і выкарыстоўваць яго для назапашвання іншага масіва.

0
дададзена