51

私の印象では、NumPy では 2 つの配列が同じメモリを共有できます。次の例を見てください。

import numpy as np
a=np.arange(27)
b=a.reshape((3,3,3))
a[0]=5000
print (b[0,0,0]) #5000

#Some tests:
a.data is b.data #False
a.data == b.data #True

c=np.arange(27)
c[0]=5000
a.data == c.data #True ( Same data, not same memory storage ), False positive

したがって、明らかに;bのコピーを作成しませんでした。aいくつかの新しいメタデータを作成し、使用している同じメモリ バッファーにアタッチしましたa。2 つの配列が同じメモリ バッファを参照しているかどうかを確認する方法はありますか?

私の第一印象は を使用することでしたa.data is b.dataが、それは false を返します。Trueを返すことはできますが、同じメモリバッファを確認して共有a.data == b.dataするためのチェックは行わないと思います。参照されるメモリブロックと参照されるブロックが同じバイトを持っていることだけです。abab

4

4 に答える 4

35

base属性を使用して、配列が別の配列とメモリを共有しているかどうかを確認できます。

>>> import numpy as np
>>> a = np.arange(27)
>>> b = a.reshape((3,3,3))
>>> b.base is a
True
>>> a.base is b
False

問題が解決するかどうかはわかりません。base 属性はNone、配列が独自のメモリを所有している場合です。サブセットであっても、配列のベースは別の配列になることに注意してください。

>>> c = a[2:]
>>> c.base is a
True
于 2012-07-02T01:30:34.033 に答える
10

jterraceの答えはおそらく最善の方法だと思いますが、別の可能性があります。

def byte_offset(a):
    """Returns a 1-d array of the byte offset of every element in `a`.
    Note that these will not in general be in order."""
    stride_offset = np.ix_(*map(range,a.shape))
    element_offset = sum(i*s for i, s in zip(stride_offset,a.strides))
    element_offset = np.asarray(element_offset).ravel()
    return np.concatenate([element_offset + x for x in range(a.itemsize)])

def share_memory(a, b):
    """Returns the number of shared bytes between arrays `a` and `b`."""
    a_low, a_high = np.byte_bounds(a)
    b_low, b_high = np.byte_bounds(b)

    beg, end = max(a_low,b_low), min(a_high,b_high)

    if end - beg > 0:
        # memory overlaps
        amem = a_low + byte_offset(a)
        bmem = b_low + byte_offset(b)

        return np.intersect1d(amem,bmem).size
    else:
        return 0

例:

>>> a = np.arange(10)
>>> b = a.reshape((5,2))
>>> c = a[::2]
>>> d = a[1::2]
>>> e = a[0:1]
>>> f = a[0:1]
>>> f = f.reshape(())
>>> share_memory(a,b)
80
>>> share_memory(a,c)
40
>>> share_memory(a,d)
40
>>> share_memory(c,d)
0
>>> share_memory(a,e)
8
>>> share_memory(a,f)
8

これは、コンピューター上share_memory(a,a[::2])の要素の数の関数として、各呼び出しの時間を示すプロットです。a

share_memory関数

于 2012-07-02T03:16:09.080 に答える
6

ただ行う:

a = np.arange(27)
a.__array_interface__['data']

2 行目はタプルを返します。最初のエントリはメモリ アドレスで、2 番目のエントリは配列が読み取り専用かどうかです。形状とデータ型を組み合わせることで、配列がカバーするメモリ アドレスの正確な範囲を把握できるため、ある配列が別の配列のサブセットである場合にも、これから計算することができます。

于 2015-03-10T14:58:39.660 に答える