अजगर शून्य के साथ सुन्न सरणी पैड करने के लिए कैसे


99

मैं जानना चाहता हूं कि मैं शून्य संस्करण के साथ एक 2 डी संख्यात्मक खांचे को पैड कर सकता हूं जो कि अजगर संस्करण 2.6.6 के साथ संख्यात्मक संस्करण 1.5.0 का उपयोग कर रहा है। माफ़ करना! लेकिन ये मेरी सीमाएँ हैं। इसलिए मैं उपयोग नहीं कर सकता 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
शानेब

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

बस के मामले में दूसरा तर्क ( [(0, 1), (0, 1)]) भ्रामक लगता है: प्रत्येक सूची आइटम (इस मामले में टुपल) एक आयाम से मेल खाती है और उसमें आइटम पहले (पहले तत्व) और उसके बाद (दूसरे तत्व) पैडिंग का प्रतिनिधित्व करता है । इसलिए:

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

इस मामले में पहली और दूसरी धुरी के लिए पैडिंग एक समान है, इसलिए कोई भी 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.]])

या यदि पहले और बाद में पैडिंग समान है लेकिन अक्ष के लिए अलग है, तो आप आंतरिक ट्यूल में दूसरा तर्क भी छोड़ सकते हैं:

>>> 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
यह वास्तव में अच्छी तरह से समझाया गया है। मूल प्रलेखन की तुलना में बेहतर है। धन्यवाद।
एम। इननाट

mode='constant'समझदार डिफ़ॉल्ट है, इसलिए शून्य के साथ पैडिंग किसी भी वैकल्पिक कीवर्ड की आवश्यकता के बिना प्राप्त की जा सकती है, जिससे थोड़ा अधिक पठनीय कोड हो सकता है।
दिव्यंग

मैं केवल 3 डी अंक के सरणी के तीसरे आयाम में पैडिंग कैसे जोड़ सकता हूं?
रमशा सिद्दीकी

@ रामशिक्की आप उन आयामों के लिए 0s का उपयोग कर सकते हैं जिन्हें गद्देदार नहीं होना चाहिए।
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.]]

सच है, अपने विशिष्ट मामले के लिए, उसे जरूरी पैड की जरूरत नहीं है, लेकिन यह बहुत कम अंकगणितीय ऑपरेशनों में से एक है जहां पैडिंग और आपका दृष्टिकोण बराबर है। फिर भी अच्छा जवाब!
MSeifert

1
इतना ही नहीं। यह शून्य-गद्दी की तुलना में अधिक स्मृति कुशल भी हो सकता है।
नॉरोक 2

0

मामले में आपको एक सरणी में 1s की बाड़ जोड़ने की आवश्यकता है:

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

जटिलता विश्लेषण:

इसके लिए इष्टतम समाधान सुन्न की पैड विधि है। 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%
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.