2

さまざまな種類の要素のリストを保存してアクセスする必要がある Python コードをいくつか書いています。このリストの各要素は、異なるクラス タイプになります。例えば:

def file_len(fname):
    i = 0
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1

element_list = [ ]
data = np.loadtxt(filename)


if file_len(filename) == 1 : 
            data = np.loadtxt(filename)
            param1 = data[0]
            param2 = data[1]
            element_list.append(Class1.Class1(param1,param2))
else:
    for field in data:
                    param1 = field[0]
                    param2 = field[1]
                    element_list.append(Class1.Class1(param1, param2)

後で、element_list に挿入された Class1 のメソッドに何度かアクセスする必要がありますが、リストを変更する必要はありません。

for i in xrange(10000):
    for element in element_list:
        result += element.calculate_result(i).real #the results will be complex

これを行う効率的な方法はありますか?

ありがとう!

4

2 に答える 2

1

これは完全な答えではありませんが、私が貢献できる2つのことを見つけました。

これがの改良版ですfile_len()。ファイルの長さがゼロの場合、これは0を返します。この関数は、長さがゼロのファイルの場合は1を返し、1行のファイルの場合は1を返します。

def file_len(fname):
    i = 0
    with open(fname) as f:
        for i, l in enumerate(f, 1):
            pass
    return i

これは、計算ループを実行するためのより高速な方法です。

result = sum(e.calculate_result(i).real for i in xrange(10000) for e in element_list)

を使用してさらに高速化することは可能かもしれませんがreduce()、それほど高速化できるとは思いません。の大きな節約は、名前を何度もバインドすることを回避できる場合ですが、タイプが何であっても呼び出すことができるようにreduce()、名前をバインドする必要があります。ee.calculate_result(i).reale

あなたがこのようなことをすることができれば、それは少し速いかもしれません。

import itertools as it
import operator as op
result = reduce(op.add, it.imap(SomeClass.calculate_something, it.product(element_list, xrange(10000))))

繰り返しますが、主な節約は名前のバインドを回避することです。 whereがからの要素であり、がからの数値であるit.product()タプルを返します。次に、関数を呼び出し、タプルを引数として渡します。次に、すべてを合計します。実際には、電話をかけるだけでもおそらく同じくらい良いのですが、両方の方法を試して、どちらかがもう一方よりもわずかに速いかどうかを確認できます。あなたが賢明な何かを理解することができれば、多分あなたはこの仕事をすることができます。(e, i)eelement_listixrange(10000)it.imap()reduce()sum()reduce(op.add)SomeClass.calculate_something

うーん、複素数の合計を計算させてsum()(またはreduce())、合計が完了したら虚数部を破棄してみる価値があるかもしれません。.real値ごとに1回属性にアクセスするよりも高速でしょうか?よくわかりませんが、reduce()バージョンを機能させるのに役立つ可能性があります。

編集:

PyPyでプログラムを実行してみてください。

http://pypy.org/

その場合は、最初に示した行の代わりに、必ずこの行を使用してください。

result = sum(e.calculate_result(i).real for e in element_list for i in xrange(10000))

このように、連続して10000回の呼び出しに各要素eを使用します。これは、PyPyジャストインタイムコンパイラ(「JIT」)がより良いコードを生成するのに役立ちます。JITが10000コールだけで役立つかどうかはわかりませんが、それを試す方法のようです。

于 2012-06-13T09:18:21.050 に答える
0

インスタンス化時にそのビューを渡すことにより、クラス内の結果を配列内のビューに入れることができます。クラスメソッドを呼び出してデータを更新するよりも頻繁にデータにアクセスしている場合、これは機能するはずです。

次のようなもの...

def file_len(fname):
    i = 0
    with open(fname) as f:
        for i, l in enumerate(f):
            pass
    return i + 1

element_list = [ ]
data = np.loadtxt(filename)


array_idx = 0

# length_of_data is the number of elements that will be in element_list
result_array = numpy.zeros(length_of_data, dtype='complex128')

if file_len(filename) == 1 : 
    data = np.loadtxt(filename)
    param1 = data[0]
    param2 = data[1]
    element_list.append(Class1.Class1(param1, param2, 
                            result_array[array_idx:array_idx+1]))
    array_idx += 1
else:
    for field in data:
        param1 = field[0]
        param2 = field[1]
        element_list.append(Class1.Class1(param1, param2,
                            result_array[array_idx:array_idx+1])
        array_idx += 1

クラス内では、ビューを直接更新します。この最小限の例を考えてみましょう。

import numpy

a = numpy.zeros(5, dtype='complex128')

class Foo(object):

    def __init__(self, real, imag, array_view):
        self._array_view = array_view
        self._array_view[:] = real + 1j*imag #<--- The [:] is needed


element_list = []
for n in range(0, len(a)):
    element_list.append(Foo(n, n+1, a[n:n+1]))

print(a)
print(numpy.sum(a))
于 2012-06-13T07:58:11.213 に答える