python uyuşuk diziyi sıfırlarla doldurma


96

Numpy sürüm 1.5.0 ile python 2.6.6 kullanarak 2D bir uyuşmuş diziyi nasıl sıfırlarla doldurabileceğimi bilmek istiyorum. Afedersiniz! Ama bunlar benim sınırlamalarım. Bu nedenle kullanamıyorum np.pad. Örneğin, aşekli eşleşecek şekilde sıfırlarla doldurmak istiyorum b. Bunu yapmak istememin nedeni şunları yapabilmem:

b-a

öyle ki

>>> 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]])

Bunu yapmayı düşünebilmemin tek yolu eklemek, ancak bu oldukça çirkin görünüyor. Kullanan daha temiz bir çözüm var b.shapemı?

Düzenle, MSeiferts cevabına teşekkür ederiz. Biraz temizlemek zorunda kaldım ve elimde bu:

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

Yanıtlar:


155

Çok basit, referans şeklini kullanarak sıfır içeren bir dizi oluşturursunuz:

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

ve ardından diziyi ihtiyacınız olan yere ekleyin:

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

ve işte onu doldurdun:

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.]])

Sol üst öğenizin nereye ekleneceğini tanımlarsanız, bunu biraz daha genel hale de getirebilirsiniz.

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.]])

ancak izin verilenden daha büyük ofsetlere sahip olmadığınızdan emin olun. İçin x_offset = 2bu başarısız olur mesela.


İsteğe bağlı sayıda boyutunuz varsa, orijinal diziyi eklemek için bir dilim listesi tanımlayabilirsiniz. Biraz oynamayı ilginç buldum ve dizi ve referans aynı sayıda boyuta sahip olduğu ve ofsetler çok büyük olmadığı sürece, rastgele şekilli bir diziyi (ofset ile) doldurabilen bir dolgu işlevi yarattım.

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

Ve bazı test durumları:

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)

Sadece ihtiyacım olan durumu özetlemek gerekirse: kökene rastgele boyutlar ekliyorsanız:padded = np.zeros(b.shape) padded[tuple(slice(0,n) for n in a.shape)] = a
2019

162

NumPy 1.7.0 ( numpy.padeklendiğinde) şimdi oldukça eski (2013'te piyasaya sürüldü), bu yüzden soru bu işlevi kullanmadan bir yol sorsa da, bunun nasıl elde edilebileceğini bilmenin yararlı olabileceğini düşündüm numpy.pad.

Aslında oldukça basit:

>>> 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.]])

Bu durumda 0, bu varsayılan değer olarak kullandım mode='constant'. Ancak, açıkça iletilerek de belirtilebilir:

>>> 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.]])

İkinci bağımsız değişkenin ( [(0, 1), (0, 1)]) kafa karıştırıcı görünmesi durumunda : Her liste öğesi (bu durumda demet) bir boyuta karşılık gelir ve buradaki öğe, önceki (birinci öğe) ve sonraki (ikinci öğe) dolgusunu temsil eder . Yani:

[(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.

Bu durumda, birinci ve ikinci eksen için dolgu özdeştir, bu nedenle biri 2-demetinde de geçebilir:

>>> 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.]])

Önceki ve sonraki dolgunun aynı olması durumunda, tuple bile atlanabilir (bu durumda uygulanamaz):

>>> 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.]])

Veya önceki ve sonraki dolgu eksen için aynıysa ancak farklıysa, iç tuplelardaki ikinci bağımsız değişkeni de atlayabilirsiniz:

>>> 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.]])

Bununla birlikte, her zaman açık olanı kullanmayı tercih etme eğilimindeyim, çünkü hata yapmak çok kolay (NumPys beklentileri niyetinizden farklı olduğunda):

>>> 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.]])

Burada NumPy, tüm ekseni her eksenden önce 1 ve sonra 2 öğe ile doldurmak istediğinizi düşünüyor! Eksen 1'de 1 öğe ve eksen 2 için 2 öğe ile doldurmayı amaçlasanız bile.

Dolgu için tuple listelerini kullandım, bunun sadece "benim kuralım" olduğuna dikkat edin, ayrıca listelerin veya demetlerin listelerini veya hatta dizilerin demetlerini de kullanabilirsiniz. NumPy sadece argümanın uzunluğunu (veya bir uzunluğu yoksa) ve her bir öğenin uzunluğunu (veya bir uzunluğa sahip olup olmadığını) kontrol eder!


4
Bu gerçekten iyi açıklandı. Orijinal belgelerden çok daha iyi. Teşekkürler.
M.Innat

mode='constant'mantıklı varsayılan değerdir, bu nedenle isteğe bağlı herhangi bir anahtar kelimeye ihtiyaç duyulmadan sıfırlarla doldurulabilir ve bu da biraz daha okunabilir koda yol açar.
divenex

bir 3B uyuşmuş dizinin yalnızca üçüncü boyutuna nasıl dolgu ekleyebilirim?
Ramsha Siddiqui

@RamshaSiddiqui, doldurulmaması gereken boyutlar için 0 s kullanabilirsiniz.
MSeifert

9

Ana probleminizin hesaplamanız gerektiğini anlıyorum d=b-aama dizilerinizin boyutları farklı. Ara yastığa gerek yokturc

Bunu dolgu yapmadan çözebilirsiniz:

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

Çıktı:

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

Doğru, kendi özel durumu için, mutlaka doldurması gerekmez, ancak bu, doldurma ve yaklaşımınızın eşdeğer olduğu çok az aritmetik işlemden biridir. Yine de güzel cevap!
MSeifert

1
Sadece bu da değil. Bu aynı zamanda sıfır doldurmadan daha verimli bellek olabilir.
norok2

0

Bir diziye 1s'lik bir çit eklemeniz gerekirse:

>>> 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

Buna biraz geç kaldığımı biliyorum, ancak göreli dolgu (diğer bir deyişle kenar dolgusu) yapmak istemeniz durumunda, işte bunu nasıl uygulayacağınız. Atamanın ilk örneğinin sıfır doldurma ile sonuçlandığına dikkat edin, bu nedenle bunu hem sıfır doldurma hem de göreli dolgu için kullanabilirsiniz (burası, orijinal dizinin kenar değerlerini doldurulmuş diziye kopyaladığınız yerdir).

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

Karmaşıklık Analizi:

Bunun için en uygun çözüm numpy'nin ped yöntemidir. 5 çalıştırma için ortalama alındıktan sonra, göreceli dolgulu np.pad yalnızca 8%yukarıda tanımlanan işlevden daha iyidir. Bu, bunun göreceli ve sıfır doldurma dolgusu için oldukça optimal bir yöntem olduğunu gösterir.


#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%
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.