web-dev-qa-db-ja.com

Numpy配列のスライスを交換します

pythonが変数のスワップを処理する方法が大好きです:a, b, = b, a

この機能を使用して、一度に1つだけでなく、(一時変数を使用せずに)複数の配列間で値を交換したいと思います。これは私が期待したものではありません(3番目の次元に沿った両方のエントリが両方に交換されることを望んでいました):

import numpy as np
a = np.random.randint(0, 10, (2, 3,3))
b = np.random.randint(0, 10, (2, 5,5))
# display before
a[:,0, 0]
b[:,0,0]
a[:,0,0], b[:, 0, 0] = b[:, 0, 0], a[:,0,0] #swap
# display after
a[:,0, 0]
b[:,0,0]

誰かアイデアがありますか?もちろん、いつでも追加の変数を導入できますが、これを行うためのよりエレガントな方法があるかどうか疑問に思いました。

28
user2082745

Pythonは、追加の変数を使用したかのようにコードを正しく解釈するため、スワッピングコードは次のようになります。

t1 = b[:,0,0]
t2 = a[:,0,0]
a[:,0,0] = t1
b[:,0,0] = t2

ただし、thisコードでさえ、値を正しくスワップしません!これは、Numpy slices がデータを熱心にコピーせず、既存のデータにビューを作成するためです。コピーはスライスが割り当てられた時点でのみ実行されますが、スワップする場合、中間バッファーのないコピーはデータを破壊します。これが、追加の変数だけでなく、追加のnumpyバッファーが必要な理由です。これは、一般的なPython構文は何も知ることができません。たとえば、これは期待どおりに機能します。

t = np.copy(a[:,0,0])
a[:,0,0] = b[:,0,0]
b[:,0,0] = t
21
user4815162342

私はこれが最も簡単だと思います:

a[:,0,0], b[:, 0, 0] = b[:, 0, 0], a[:, 0, 0].copy() #swap

時間比較:

%timeit a[:,0,0], b[:, 0, 0] = b[:, 0, 0], a[:, 0, 0].copy() #swap
The slowest run took 10.79 times longer than the fastest. This could mean that an intermediate result is being cached 
1000000 loops, best of 3: 1.75 µs per loop

%timeit t = np.copy(a[:,0,0]); a[:,0,0] = b[:,0,0]; b[:,0,0] = t
The slowest run took 10.88 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 2.68 µs per loop
6
blaz

ser4815162342の答え は確かに「正しい」ものです。しかし、あなたが本当にワンライナーを求めているのなら、これを考慮してください:

a[arange(2),0,0], b[arange(2), 0, 0] = b[arange(2), 0, 0], a[arange(2),0,0] #swap

ただし、これは大幅に効率が低下します。

In [12]: %timeit a[arange(2),0,0], b[arange(2), 0, 0] = b[arange(2), 0, 0], a[arange(2),0,0]
10000 loops, best of 3: 32.2 µs per loop

In [13]: %timeit t = np.copy(a[:,0,0]); a[:,0,0] = b[:,0,0]; b[:,0,0] = t
The slowest run took 4.14 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 13.3 µs per loop

(ただし、「最も遅い実行」に関する注意事項に注意してください...「-n1 -r 1」を指定して%timeitを呼び出そうとすると、より比較可能な結果が表示されます-私のソリューションではまだ約50%遅いですが-はい、キャッシングはタイミングに影響を与えています)

1