pythonnumpy配列をゼロで埋める方法


99

numpyバージョン1.5.0でpython2.6.6を使用して、2Dnumpy配列にゼロを埋め込む方法を知りたいです。ごめんなさい!しかし、これらは私の制限です。したがって、使用できませんnp.pad。たとえばa、形状がに一致するようにゼロを埋めたいとしbます。私がこれをしたい理由は私ができるようにするためです:

b-a

そのような

>>> a
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.,  1.]])
>>> b
array([[ 3.,  3.,  3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.,  3.,  3.],
       [ 3.,  3.,  3.,  3.,  3.,  3.]])
>>> c
array([[1, 1, 1, 1, 1, 0],
       [1, 1, 1, 1, 1, 0],
       [1, 1, 1, 1, 1, 0],
       [0, 0, 0, 0, 0, 0]])

私がこれを行うことを考えることができる唯一の方法は追加することです、しかしこれはかなり醜いようです。おそらく使用しているよりクリーンな解決策はありb.shapeますか?

編集、MSeifertsの回答に感謝します。私はそれを少しきれいにしなければなりませんでした、そしてこれは私が得たものです:

def pad(array, reference_shape, offsets):
    """
    array: Array to be padded
    reference_shape: tuple of size of ndarray to create
    offsets: list of offsets (number of elements must be equal to the dimension of the array)
    will throw a ValueError if offsets is too big and the reference_shape cannot handle the offsets
    """

    # Create an array of zeros with the reference shape
    result = np.zeros(reference_shape)
    # Create a list of slices from offset to offset + shape in each dimension
    insertHere = [slice(offsets[dim], offsets[dim] + array.shape[dim]) for dim in range(array.ndim)]
    # Insert the array in the result at the specified offsets
    result[insertHere] = array
    return result

回答:


161

非常に簡単です。参照形状を使用して、ゼロを含む配列を作成します。

result = np.zeros(b.shape)
# actually you can also use result = np.zeros_like(b) 
# but that also copies the dtype not only the shape

次に、必要な場所に配列を挿入します。

result[:a.shape[0],:a.shape[1]] = a

そして、あなたがそれを埋めた出来上がり:

print(result)
array([[ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.]])

左上の要素を挿入する場所を定義すると、もう少し一般的にすることもできます

result = np.zeros_like(b)
x_offset = 1  # 0 would be what you wanted
y_offset = 1  # 0 in your case
result[x_offset:a.shape[0]+x_offset,y_offset:a.shape[1]+y_offset] = a
result

array([[ 0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  1.,  1.,  1.,  1.,  1.],
       [ 0.,  1.,  1.,  1.,  1.,  1.]])

ただし、許可されているよりも大きなオフセットがないように注意してください。たとえばx_offset = 2、これは失敗します。


任意の数の次元がある場合は、スライスのリストを定義して元の配列を挿入できます。少し遊んでみると面白いと思い、配列と参照の次元数が同じでオフセットが大きすぎない限り、任意の形状の配列を(オフセットで)パディングできるパディング関数を作成しました。

def pad(array, reference, offsets):
    """
    array: Array to be padded
    reference: Reference array with the desired shape
    offsets: list of offsets (number of elements must be equal to the dimension of the array)
    """
    # Create an array of zeros with the reference shape
    result = np.zeros(reference.shape)
    # Create a list of slices from offset to offset + shape in each dimension
    insertHere = [slice(offset[dim], offset[dim] + array.shape[dim]) for dim in range(a.ndim)]
    # Insert the array in the result at the specified offsets
    result[insertHere] = a
    return result

そしていくつかのテストケース:

import numpy as np

# 1 Dimension
a = np.ones(2)
b = np.ones(5)
offset = [3]
pad(a, b, offset)

# 3 Dimensions

a = np.ones((3,3,3))
b = np.ones((5,4,3))
offset = [1,0,0]
pad(a, b, offset)

ちょうど私が必要なケースを要約する:原点に挿入し、任意の大きさならば:padded = np.zeros(b.shape) padded[tuple(slice(0,n) for n in a.shape)] = a
shaneb

169

NumPy 1.7.0(numpy.pad追加されたとき)はかなり古い(2013年にリリースされた)ので、その関数を使用せずに方法尋ねられたとしても、を使用してそれを実現する方法を知ることは有用だと思いましたnumpy.pad

それは実際にはかなり簡単です:

>>> import numpy as np
>>> a = np.array([[ 1.,  1.,  1.,  1.,  1.],
...               [ 1.,  1.,  1.,  1.,  1.],
...               [ 1.,  1.,  1.,  1.,  1.]])
>>> np.pad(a, [(0, 1), (0, 1)], mode='constant')
array([[ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.]])

この場合、私はそれを使用し0ましたmode='constant'。これはのデフォルト値です。ただし、明示的に渡すことで指定することもできます。

>>> np.pad(a, [(0, 1), (0, 1)], mode='constant', constant_values=0)
array([[ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.]])

2番目の引数([(0, 1), (0, 1)])がわかりにくい場合に備えて、各リスト項目(この場合はタプル)は次元に対応し、その中の項目は(最初の要素)と(2番目の要素)のパディングを表します。そう:

[(0, 1), (0, 1)]
         ^^^^^^------ padding for second dimension
 ^^^^^^-------------- padding for first dimension

  ^------------------ no padding at the beginning of the first axis
     ^--------------- pad with one "value" at the end of the first axis.

この場合、1番目と2番目の軸のパディングは同じであるため、2タプルを渡すこともできます。

>>> np.pad(a, (0, 1), mode='constant')
array([[ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.]])

前後のパディングが同じである場合、タプルを省略することもできます(ただし、この場合は適用されません)。

>>> np.pad(a, 1, mode='constant')
array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.]])

または、前後のパディングが同じであるが軸が異なる場合は、内側のタプルの2番目の引数を省略することもできます。

>>> np.pad(a, [(1, ), (2, )], mode='constant')
array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])

ただし、間違いを犯しやすいため(NumPysの期待が意図と異なる場合)、常に明示的なものを使用することを好む傾向があります。

>>> np.pad(a, [1, 2], mode='constant')
array([[ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  1.,  1.,  1.,  1.,  1.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])

ここで、NumPyは、すべての軸を各軸の前に1つの要素、後に2つの要素で埋めたいと考えています。軸1に1つの要素、軸2に2つの要素を埋めることを意図した場合でも。

パディングにはタプルのリストを使用しました。これは単なる「私の慣習」であることに注意してください。リストのリストまたはタプルのタプル、さらには配列のタプルを使用することもできます。NumPyは、引数の長さ(または長さがない場合)と各項目の長さ(または長さがある場合)をチェックするだけです!


5
それは本当によく説明されています。元のドキュメントよりもはるかに優れています。ありがとう。
M.Innat 2018

mode='constant'は賢明なデフォルトであるため、オプションのキーワードを必要とせずにゼロを埋めることができ、コードが少し読みやすくなります。
divenex

3D numpy配列の3次元にのみパディングを追加するにはどうすればよいですか?
RamshaSiddiqui20年

@RamshaSiddiquiは、パディングされるべきではない次元に0を使用できます。
MSeifert

9

あなたの主な問題は計算する必要があることですd=b-aが、配列のサイズが異なることを理解しています。中間のパッドは必要ありませんc

パディングなしでこれを解決できます:

import numpy as np

a = np.array([[ 1.,  1.,  1.,  1.,  1.],
              [ 1.,  1.,  1.,  1.,  1.],
              [ 1.,  1.,  1.,  1.,  1.]])

b = np.array([[ 3.,  3.,  3.,  3.,  3.,  3.],
              [ 3.,  3.,  3.,  3.,  3.,  3.],
              [ 3.,  3.,  3.,  3.,  3.,  3.],
              [ 3.,  3.,  3.,  3.,  3.,  3.]])

d = b.copy()
d[:a.shape[0],:a.shape[1]] -=  a

print d

出力:

[[ 2.  2.  2.  2.  2.  3.]
 [ 2.  2.  2.  2.  2.  3.]
 [ 2.  2.  2.  2.  2.  3.]
 [ 3.  3.  3.  3.  3.  3.]]

確かに、彼の特定のケースでは、必ずしもパディングする必要はありませんが、パディングとアプローチが同等である数少ない算術演算の1つです。それにもかかわらず、いい答えです!
MSeifert 2016年

1
それだけでなく。これは、ゼロパディングよりもメモリ効率が高い可能性もあります。
norok2 2018

0

配列に1のフェンスを追加する必要がある場合:

>>> mat = np.zeros((4,4), np.int32)
>>> mat
array([[0, 0, 0, 0],
       [0, 0, 0, 0],
       [0, 0, 0, 0],
       [0, 0, 0, 0]])
>>> mat[0,:] = mat[:,0] = mat[:,-1] =  mat[-1,:] = 1
>>> mat
array([[1, 1, 1, 1],
       [1, 0, 0, 1],
       [1, 0, 0, 1],
       [1, 1, 1, 1]])

0

私はこれに少し遅れていることを知っていますが、相対的なパディング(別名エッジパディング)を実行したい場合は、これを実装する方法を説明します。割り当ての最初のインスタンスはゼロパディングになるため、これをゼロパディングと相対パディングの両方に使用できることに注意してください(これは、元の配列のエッジ値をパディングされた配列にコピーする場所です)。

def replicate_padding(arr):
    """Perform replicate padding on a numpy array."""
    new_pad_shape = tuple(np.array(arr.shape) + 2) # 2 indicates the width + height to change, a (512, 512) image --> (514, 514) padded image.
    padded_array = np.zeros(new_pad_shape) #create an array of zeros with new dimensions
    
    # perform replication
    padded_array[1:-1,1:-1] = arr        # result will be zero-pad
    padded_array[0,1:-1] = arr[0]        # perform edge pad for top row
    padded_array[-1, 1:-1] = arr[-1]     # edge pad for bottom row
    padded_array.T[0, 1:-1] = arr.T[0]   # edge pad for first column
    padded_array.T[-1, 1:-1] = arr.T[-1] # edge pad for last column
    
    #at this point, all values except for the 4 corners should have been replicated
    padded_array[0][0] = arr[0][0]     # top left corner
    padded_array[-1][0] = arr[-1][0]   # bottom left corner
    padded_array[0][-1] = arr[0][-1]   # top right corner 
    padded_array[-1][-1] = arr[-1][-1] # bottom right corner

    return padded_array

複雑さの分析:

これに対する最適な解決策は、numpyのパッド法です。5回の実行で平均化した後、相対パディングを使用したnp.padは、8%上記で定義した関数よりも優れています。これは、これが相対パディングおよびゼロパディングパディングにかなり最適な方法であることを示しています。


#My method, replicate_padding
start = time.time()
padded = replicate_padding(input_image)
end = time.time()
delta0 = end - start

#np.pad with edge padding
start = time.time()
padded = np.pad(input_image, 1, mode='edge')
end = time.time()
delta = end - start


print(delta0) # np Output: 0.0008790493011474609 
print(delta)  # My Output: 0.0008130073547363281
print(100*((delta0-delta)/delta)) # Percent difference: 8.12316715542522%
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.