拡張代入を使用する組み込みの `sum()`に相当するものはありますか?


8

次の関数に相当する標準ライブラリ/ numpyがありますか?

def augmented_assignment_sum(iterable, start=0):
    for n in iterable:
        start += n
    return start

一方でsum(ITERABLE)非常にエレガントで、それが使用する+演算子を代わりに+=した場合にどの、np.ndarrayオブジェクトのパフォーマンスに影響を与える可能性があります。

私は私の機能が同じくらい速いかもしれないことをテストしましたsum()(それと同等の使用+ははるかに遅いです)。それは純粋なPython関数なので、そのパフォーマンスはまだハンディキャップがあると思います。したがって、いくつかの代替策を探しています。

In [49]: ARRAYS = [np.random.random((1000000)) for _ in range(100)]

In [50]: def not_augmented_assignment_sum(iterable, start=0): 
    ...:     for n in iterable: 
    ...:         start = start + n 
    ...:     return start 
    ...:                                                                                                                                                                                                                                                                       

In [51]: %timeit not_augmented_assignment_sum(ARRAYS)                                                                                                                                                                                                                          
63.6 ms ± 8.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [52]: %timeit sum(ARRAYS)                                                                                                                                                                                                                                                   
31.2 ms ± 2.18 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [53]: %timeit augmented_assignment_sum(ARRAYS)                                                                                                                                                                                                                              
31.2 ms ± 4.73 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [54]: %timeit not_augmented_assignment_sum(ARRAYS)                                                                                                                                                                                                                          
62.5 ms ± 12.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [55]: %timeit sum(ARRAYS)                                                                                                                                                                                                                                                   
37 ms ± 9.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [56]: %timeit augmented_assignment_sum(ARRAYS)                                                                                                                                                                                                                              
27.7 ms ± 2.53 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

私はとfunctools.reduce組み合わせて使用しようとしましたoperator.iaddが、そのパフォーマンスは似ています:

In [79]: %timeit reduce(iadd, ARRAYS, 0)                                                                                                                                                                                                                                       
33.4 ms ± 11.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [80]: %timeit reduce(iadd, ARRAYS, 0)                                                                                                                                                                                                                                       
29.4 ms ± 2.31 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

また、メモリ効率にも関心があります。中間オブジェクトの作成を必要としないため、拡張割り当てをお勧めします。


np.add.reduce(ARRAYS)
ダニMesejo

1
@DanielMesejo悲しいことに374 ms ± 83.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each):-( ARRAYS2D配列の方がかなり高速ですが
abukaj


@DanielMesejoで呼び出されない限り、スカラーを返しますaxis=0。それから355 ms ± 16.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each):-(内部的に使用しますnp.add.reduce()(numpy v。1.15.4)
abukaj '15年

についてはどうですかnp.dot(your_array, np.ones(len(your_array)))。BLASに転送し、かなり迅速に処理する必要があります。
user228395

回答:


2

見出しの質問への回答--- @Martijn Pietersが私の比喩の選択を許してくれることを願っています---馬の口から直接:いいえ、そのような組み込みはありません。

数行のコードで同等のコードを実装できるようにすると、オペランドのサイズに応じて最も高速なものを備えたかなり複雑な図が得られます。

ここに画像の説明を入力してください

このグラフはsum、オペランドサイズを超えた場合のさまざまなメソッドのタイミングを示しています。項の数は常に100です。augmented_assignment_sum比較的大きなオペランドサイズに向けて効果が現れ始めます。scipy.linalg.blas.*axpyテストした範囲の大部分で使用するとかなり競争力があるように見えますが、その主な欠点は、と比べて使いやすさがはるかに劣ることですsum

コード:

from simple_benchmark import BenchmarkBuilder, MultiArgument
import numpy as np
from scipy.linalg import blas

B = BenchmarkBuilder()

@B.add_function()
def augmented_assignment_sum(iterable, start=0):
    for n in iterable:
        start += n
    return start

@B.add_function()
def not_augmented_assignment_sum(iterable, start=0):
    for n in iterable:
        start = start + n
    return start

@B.add_function()
def plain_sum(iterable, start=0):
    return sum(iterable,start)

@B.add_function()
def blas_sum(iterable, start=None):
    iterable = iter(iterable)
    if start is None:
        try:
            start = next(iterable).copy()
        except StopIteration:
            return 0
    try:
        f = {np.dtype('float32'):blas.saxpy,
             np.dtype('float64'):blas.daxpy,
             np.dtype('complex64'):blas.caxpy,
             np.dtype('complex128'):blas.zaxpy}[start.dtype]
    except KeyError:
        f = blas.daxpy
        start = start.astype(float)
    for n in iterable:
        f(n,start)
    return start

@B.add_arguments('size of terms')
def argument_provider():
    for exp in range(1,21):
        sz = int(2**exp)
        yield sz,[np.random.randn(sz) for _ in range(100)]

r = B.run()
r.plot(relative_to=plain_sum)

import pylab
pylab.savefig('inplacesum.png')

私は、見出しqusetionに技術的ではない答えを知っているが、私はこれが興味を持っているもののOPの一種であると仮定します。
ポール・パンツァー

1
見出しの質問に答えるために欠けているものは1つだけです。私が求めているそのような機能はないという声明です。;)
abukaj

1
@abukaj:そのような機能はありません。
Martijn Pieters

1
@MartijnPietersそれは私がそれを見つけられなかった理由を説明するかもしれません。;)
abukaj
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.