1

I am quite new to python and have read lots of SO questions on this topic however none of them answers my needs.

I end up with an ndarray:

[[1, 2, 3]
 [4, 5, 6]]

Now I want to pad each element (e.g. [1, 2, 3]) with a tailored padding just for that element. Of course I could do it in a for loop and append each result to a new ndarray but isn't there a faster and cleaner way I could apply this over the whole ndarray at once?

I imagined it could work like:

myArray = [[1, 2, 3]
           [4, 5, 6]]

paddings = [(1, 2),
            (2, 1)]

myArray = np.pad(myArray, paddings, 'constant')

But of course this just outputs:

[[0 0 0 0 0 0 0 0 0]
 [0 0 1 2 3 0 0 0 0]
 [0 0 3 4 5 0 0 0 0]
 [0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0]]

Which is not what i need. The target result would be:

[[0 1 2 3 0 0]
 [0 0 4 5 6 0]]

How can I achieve this using numpy?

kmario23
  • 57,311
  • 13
  • 161
  • 150
Melron
  • 459
  • 4
  • 14
  • 1
    You can't have a numpy array with elements whose shapes differ... You'd have to either accept that you need to have some default values for the padding or fall back to a Python list of lists... Could you perhaps give more context on why you want to do this? There could well be other solutions depending on why. – Jon Clements Apr 27 '19 at 15:19
  • Oh thank you for pointing that out! Sorry, the shape would end up being the same of course! I gave u a bad example! Gonna edit it now – Melron Apr 27 '19 at 15:22
  • 1
    Errr... what happened to 6? – Jon Clements Apr 27 '19 at 15:24
  • haha corrected now – Melron Apr 27 '19 at 15:28
  • I've made a small edit and added some tags so people that can answer this have the chance to see it... In the mean time, it'd be nice if you could explain how your padding is intended to work for your example - just a bit of rationale of your logic etc... it'd definitely make it easier for someone to answer... (eg: I'm doing this, and when I supply X, it does Y to my row, because Z...) – Jon Clements Apr 27 '19 at 15:32

1 Answers1

1

Here is a loop based solution but with creating a zeros array as per the dimensions of input array and paddings. Explanation in comments:

In [192]: myArray
Out[192]: 
array([[1, 2, 3],
       [4, 5, 6]])

In [193]: paddings
Out[193]: 
array([[1, 2],
       [2, 1]])

# calculate desired shape; needed for initializing `padded_arr`
In [194]: target_shape = (myArray.shape[0], myArray.shape[1] + paddings.shape[1] + 1)

In [195]: padded_arr = np.zeros(target_shape, dtype=np.int32)

In [196]: padded_arr
Out[196]: 
array([[0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0]], dtype=int32)

After this, we can use a for loop to slot fill the sequences from myArray, based on the values from paddings:

In [199]: for idx in range(paddings.shape[0]):
     ...:     padded_arr[idx, paddings[idx, 0]:-paddings[idx, 1]] = myArray[idx]
     ...:     

In [200]: padded_arr
Out[200]: 
array([[0, 1, 2, 3, 0, 0],
       [0, 0, 4, 5, 6, 0]], dtype=int32)

The reason we've to resort to a loop based solution is because numpy.lib.pad() doesn't yet support this sort of padding, even with all available additional modes and keyword arguments that it already provides.

kmario23
  • 57,311
  • 13
  • 161
  • 150