I want to create an array of a given shape based on another numpy array. The number of dimensions will be matching, but the sizes will differ from axis to axis. If the original size is too small, I want to pad it with zeros to fulfill the requirements. Example of expected behaviour to clarify:
embedding = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8]
])
resize_with_outer_zeros(embedding, (4, 3)) = np.array([
[1, 2, 3],
[5, 6, 7],
[0, 0, 0],
[0, 0, 0]
])
I think I achieved the desired behaviour with the function below.
def resize_with_outer_zeros(embedding: np.ndarray, target_shape: Tuple[int, ...]) -> np.ndarray:
padding = tuple((0, max(0, target_size - size)) for target_size, size in zip(target_shape, embedding.shape))
target_slice = tuple(slice(0, target_size) for target_size in target_shape)
return np.pad(embedding, padding)[target_slice]
However, I have strong doubts about its efficiency and elegance, as it involves a lot of pure python tuple operations. Is there a better and more concise way to do it?
If you know that your array won't be bigger than some size (r, c)
, why not just:
def pad_with_zeros(A, r, c):
out = np.zeros((r, c))
r_, c_ = np.shape(A)
out[0:r_, 0:c_] = A
return out
If you want to support arbitrary dimensions (tensors) it gets a little uglier, but the principle remains the same:
def pad(A, shape):
out = np.zeros(shape)
out[tuple(slice(0, d) for d in np.shape(A))] = A
return out
And to support larger arrays (larger than what you would pad):
def pad(A, shape):
shape = np.max([np.shape(A), shape], axis=0)
out = np.zeros(shape)
out[tuple(slice(0, d) for d in np.shape(A))] = A
return out
I don't think you can do much better, but instead of using pad
and then slicing, just do zeros
at the right size and then an assignment - this cuts it to one list comprehension instead of two.
embedding = np.array([
[1, 2, 3, 4],
[5, 6, 7, 8]
])
z = np.zeros((4,3))
s = tuple([slice(None, min(za,ea)) for za,ea in zip(z.shape, embedding.shape)])
z[s] = embedding[s]
z
# array([[1., 2., 3.],
# [5., 6., 7.],
# [0., 0., 0.],
# [0., 0., 0.]])
I'd just use a zero-matrix and run a nested for-loop to set the values from the older array - the remaining places will automatically be padded with zeros.
import numpy as np
def resize_array(array, new_size):
Z = np.zeros(new_size)
for i in range(len(Z)):
for j in range(len(Z[i])):
try:
Z[i][j] = array[i][j]
except IndexError: # just in case array[i][j] doesn't exist in the new size and should be truncated
pass
return Z
embedding = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
print(resize_array(embedding, (4, 3)))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.