1

次のコードを確認してください。これは、除数関数の 1 つである Python で実装された sigma_2 関数 (粗ふるいを使用) の一部ですhttp://mathworld.wolfram.com/DivisorFunction.html

from time import time
from itertools import count
import numpy

def sig2(N, nump=False):
    init = time()


    #initialize array with value=1 since every positive integer is divisible by 1
    if nump:
        print 'using numpy'
        nums = numpy.ones((N,), dtype=numpy.int64)
    else:        
        nums = [1 for i in xrange(1, N)]

    #for each number n < N, add n*n to n's multiples
    for n in xrange(2, N):
        nn = n*n
        for i in count(1):
            if n*i >= N: break
            nums[n*i-1] += nn

    print 'sig2(n) done - {} ms'.format((time()-init)*1000)

さまざまな値で試してみましたが、numpy では非常に残念です。

2000 年の場合:

sig2(n) done - 4.85897064209 ms
took : 33.7610244751 ms
using numpy
sig2(n) done - 31.5930843353 ms
took : 55.6900501251 ms

200000 の場合:

sig2(n) done - 1113.80600929 ms
took : 1272.8869915 ms
using numpy
sig2(n) done - 4469.48194504 ms
took : 4705.97100258 ms

それは続き、私のコードは実際にはスケーラブルではありません-O(n)ではないためですが、これら2つとこれら2つの結果に加えて、numpyを使用するとパフォーマンスの問題が発生します。numpy は Python のリストや辞書よりも高速であるべきではありませんか? 以上が私のnumpyに対する印象でした。

4

2 に答える 2

6

@unutbu が言ったように、ベクトル化された操作を使用すると、numpy は本当に優れています。numpy を使用した最適化された実装を次に示します (Mathworld の除数関数の定義と一致しています)。

import numpy as np

def sig2_numpy(N):

    x = np.arange(1,N+1)
    x[(N % x) != 0] = 0
    return np.sum(x**2)

それを呼び出すと、はるかに高速になります。

>> import time
>> init = time.time()
>> print sig2_numpy(20000)
>> print "It took", (time.time()-init)*1000., 'ms'
It took 0.916957855225 ms
于 2012-11-14T10:53:54.040 に答える
3

NumPy は、一度に 1 つの値ではなく、配列全体に対して計算を実行することで速度を達成します。

あなたが書くとき

    for i in count(1):
        if n*i >= N: break
        nums[n*i-1] += nn

NumPy 配列numsに、配列内の単一の値を一度に 1 つのインデックスずつインクリメントするように強制しています。これは、NumPy 配列の操作が遅くなります。

于 2012-11-14T10:36:16.330 に答える