11

いくつかのバイオインフォマティクスの作業を行う際に、Python リストではなく Numpy 配列にオブジェクト インスタンスを格納することの影響について熟考してきましたが、行ったすべてのテストで、すべてのインスタンスでパフォーマンスが低下しました。私はCPythonを使用しています。その理由を知っている人はいますか?

具体的には:

  • 固定長配列numpy.ndarray(dtype=object)と通常の Python リストを使用すると、パフォーマンスにどのような影響がありますか? 私が行った最初のテストでは、Numpy 配列要素へのアクセスは、特にオブジェクト メソッドを使用する場合に、Python リストを介した反復よりも遅いことが示されました。
  • [ X() for i in range(n) ]の代わりになどのリスト内包表記を使用してオブジェクトをインスタンス化する方が速いのはなぜnumpy.empty(size=n, dtype=object)ですか?
  • それぞれのメモリ オーバーヘッドはどれくらいですか? これをテストできませんでした。私のクラスは、影響がある場合は を広く使用__slots__しています。
4

1 に答える 1

21

このような場合、numpy でオブジェクト配列を使用しないでください。

それらは numpy 配列の基本的な目的を無効にし、ほんの一握りの状況で役立ちますが、ほとんどの場合、適切な選択ではありません。

はい、python で numpy 配列の個々の要素にアクセスするか、python で numpy 配列を反復処理すると、list. y = [item * 2 for item in x](これが、 when xis a numpy array のようなことを決してすべきではない理由です。)

Numpy オブジェクト配列は、リストよりもメモリ オーバーヘッドがわずかに低くなりますが、多数の個別の Python オブジェクトを保存している場合は、最初に他のメモリの問題が発生します。

Numpy は何よりもまず、均一な数値データ用のメモリ効率の高い多次元配列コンテナーです。numpy 配列に任意のオブジェクトを保持したい場合は、代わりにおそらくリストが必要です。


私のポイントは、numpy を効果的に使用したい場合は、構造化の方法を再考する必要があるかもしれないということです。

各オブジェクトインスタンスをnumpy配列に保存する代わりに、数値データをnumpy配列に保存し、行/列などごとに個別のオブジェクトが必要な場合は、各インスタンスのその配列にインデックスを保存します。

このようにして、数値配列をすばやく操作できます (つまり、リスト内包表記の代わりに numpy を使用します)。

私が話していることの簡単な例として、numpy を使用しない簡単な例を次に示します。

from random import random

class PointSet(object):
    def __init__(self, numpoints):
        self.points = [Point(random(), random()) for _ in xrange(numpoints)]

    def update(self):
        for point in self.points:
            point.x += random() - 0.5
            point.y += random() - 0.5

class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

points = PointSet(100000)
point = points.points[10]

for _ in xrange(1000):
    points.update()
    print 'Position of one point out of 100000:', point.x, point.y

numpy 配列を使用した同様の例:

import numpy as np

class PointSet(object):
    def __init__(self, numpoints):
        self.coords = np.random.random((numpoints, 2))
        self.points = [Point(i, self.coords) for i in xrange(numpoints)]

    def update(self):
        """Update along a random walk."""
        # The "+=" is crucial here... We have to update "coords" in-place, in
        # this case. 
        self.coords += np.random.random(self.coords.shape) - 0.5

class Point(object):
    def __init__(self, i, coords):
        self.i = i
        self.coords = coords

    @property
    def x(self):
        return self.coords[self.i,0]

    @property
    def y(self):
        return self.coords[self.i,1]


points = PointSet(100000)
point = points.points[10]

for _ in xrange(1000):
    points.update()
    print 'Position of one point out of 100000:', point.x, point.y

これを行う方法は他にもあります (たとえば、特定のnumpy 配列への参照を each に保存したくない場合がありますpoint) が、これが役立つ例であることを願っています。

走る速さの違いに注目。私のマシンでは、numpy バ​​ージョンでは 5 秒、pure-python バージョンでは 60 秒の差があります。

于 2012-06-27T19:10:06.127 に答える