これは、dtype uint8 の 3 番目の配列と bool 配列を作成することで実現できます(これらを組み合わせると、1 つの uint16 配列よりもメモリ効率が高くなります)。
np.putmask
一時配列を回避するのに役立ちます。
a = np.array([100, 200, 250], dtype=np.uint8)
b = np.array([50, 50, 50], dtype=np.uint8)
c = 255 - b # a temp uint8 array here
np.putmask(a, c < a, c) # a temp bool array here
a += b
ただし、@ moarningsun が正しく指摘しているように、bool 配列は uint8 配列と同じ量のメモリを使用するため、これは必ずしも役に立ちません。任意の時点で複数の一時配列を持たないようにすることで、これを解決できます。
a = np.array([100, 200, 250], dtype=np.uint8)
b = np.array([50, 50, 50], dtype=np.uint8)
b = 255 - b # old b is gone shortly after new array is created
np.putmask(a, b < a, b) # a temp bool array here, then it's gone
a += 255 - b # a temp array here, then it's gone
このアプローチは、CPU とメモリ消費を交換します。
もう 1 つの方法は、考えられるすべての結果を事前に計算することです。これは、O(1) の余分なメモリです (つまり、配列のサイズに関係なく)。
c = np.clip(np.arange(256) + np.arange(256)[..., np.newaxis], 0, 255).astype(np.uint8)
c
=> array([[ 0, 1, 2, ..., 253, 254, 255],
[ 1, 2, 3, ..., 254, 255, 255],
[ 2, 3, 4, ..., 255, 255, 255],
...,
[253, 254, 255, ..., 255, 255, 255],
[254, 255, 255, ..., 255, 255, 255],
[255, 255, 255, ..., 255, 255, 255]], dtype=uint8)
c[a,b]
=> array([150, 250, 255], dtype=uint8)
配列が非常に大きい場合は、この方法が最もメモリ効率が高くなります。繰り返しになりますが、超高速の整数加算を低速の 2dim-array インデックス付けに置き換えるため、処理時間が長くなります。
仕組みの説明
上記の配列の構築にはc
、numpy ブロードキャスト トリックが使用されます。(N,)
形状の配列と形状(1,N)
ブロードキャストの配列を追加すると、両方とも のようになります(N,N)
。したがって、結果はすべての可能な合計の NxN 配列になります。次に、クリップします。次を満たす 2dim 配列を取得しc[i,j]=min(i+j,255)
ます。
残っているのは、適切な値を取得するために凝ったインデックスを使用することです。提供された入力を使用して、以下にアクセスします。
c[( [100, 200, 250] , [50, 50, 50] )]
最初のインデックス配列は 1 番目の次元を参照し、2 番目は 2 番目の次元を参照します。したがって、結果はインデックス配列 ( (N,)
) と同じ形状の配列で、値で構成されます[ c[100,50] , c[200,50] , c[250,50] ]
。