web-dev-qa-db-ja.com

オブジェクトの数の多い配列

私はPythonでラティスモデル(ラティスボルツマン)のシミュレーションを実装しようとしています。ラティスの各サイトにはいくつかのプロパティがあり、特定のルールに従って隣接サイトと相互作用します。すべてのプロパティを持つクラスを作成し、そのクラスのインスタンスのグリッドを作成するのが賢明であると考えました。 (私はPythonに慣れていないので、これはまったく良い考えではないかもしれないので、私のアプローチについて自由にコメントしてください。)

これは私がやっていることのおもちゃの例です

class site:
    def __init__(self,a,...):
        self.a = a
        .... other properties ...
    def set_a(self, new_a):
        self.a = new_a

次に、そのようなサイトの2D/3Dラティス(グリッド)を処理したいので、次のことを試みました(ここでは例として2D 3x3グリッドですが、シミュレーションでは> 1000x1000X1000のオーダーが必要になります)。

lattice = np.empty( (3,3), dtype=object)
lattice[:,:] = site(3)

ここでの問題は、各格子点が同じインスタンスを参照することです。たとえば、

lattice[0,0].set_a(5)

また、lattice [0,2] .aの値を5に設定します。この動作は望ましくありません。問題を回避するために、各グリッドポイントをループして、要素ごとにオブジェクトを割り当てることができます。

for i in range(3):
    for j in range(3):
        lattice[i,j] = site(a)

しかし、オブジェクトを多次元配列に割り当てる(ループを含まない)より良い方法はありますか?

ありがとう

23
jonalm

あなたはできる vectorize クラスの__init__ 関数:

import numpy as np

class Site:
    def __init__(self, a):
        self.a = a
    def set_a(self, new_a):
        self.a = new_a

vSite = np.vectorize(Site)

init_arry = np.arange(9).reshape((3,3))

lattice = np.empty((3,3), dtype=object)
lattice[:,:] = vSite(init_arry)

これは見た目はきれいに見えるかもしれませんが、ループソリューションに比べてパフォーマンス上の利点はありません。リスト内包解答は、パフォーマンスに影響を与える中間のpythonリストを作成します。

27
Paul

Pythonはすべてを参照として扱います)(値のように扱われる「不変」オブジェクト、文字列、数値、およびタプルがいくつかあります)。

lattice[:,:] = site(3)

「Python:新しいオブジェクトsiteを作成し、latticeのすべての要素にそのオブジェクトを指すように指示します。」これが実際に該当することを確認するには、配列を出力して、オブジェクトのメモリアドレスがすべて同じであることを確認します。

array([[<__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>],
       [<__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>],
       [<__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>,
        <__main__.Site object at 0x1029d5610>]], dtype=object)

ループの方法は、それを行うための1つの正しい方法です。 numpy配列では、これが最良のオプションになる場合があります。 Pythonリストの場合、リスト内包表記を使用することもできます。

lattice = [ [Site(i + j) for i in range(3)] for j in range(3) ]

numpy.array構造でリスト内包表記を使用できます。

lattice = np.array( [ [Site(i + j) for i in range(3)] for j in range(3) ],
                    dtype=object)

latticeを印刷すると、

array([[<__main__.Site object at 0x1029d53d0>,
        <__main__.Site object at 0x1029d50d0>,
        <__main__.Site object at 0x1029d5390>],
       [<__main__.Site object at 0x1029d5750>,
        <__main__.Site object at 0x1029d57d0>,
        <__main__.Site object at 0x1029d5990>],
       [<__main__.Site object at 0x1029d59d0>,
        <__main__.Site object at 0x1029d5a10>,
        <__main__.Site object at 0x1029d5a50>]], dtype=object)

そこにあるすべてのオブジェクトが一意であることがわかります。

また、「setter」および「getter」メソッド(例:set_a)はPythonに準拠していないことにも注意してください。属性を直接設定および取得し、属性への書き込みアクセスを本当に防ぐ必要がある場合は、@propertyデコレーターを使用することをお勧めします。

また、Pythonクラスは、小文字ではなくCamelCaseを使用して記述されるのが標準であることに注意してください。

7
Seth Johnson

よくわかりませんが、明示的なループのセットの代わりに、次のように書くことができます

lattice = np.empty( (3,3), dtype=object)
lattice.flat = [site(3) for _ in lattice.flat]

これは、ラティスの形状が何であっても機能するはずです。

6
DSM