2016-03-02 13 views
16

Tôi muốn biết làm thế nào tôi có thể pad một mảng numpy 2D với số không bằng cách sử dụng python 2.6.6 với phiên bản numpy 1.5.0. Lấy làm tiếc! Nhưng đây là những hạn chế của tôi. Do đó tôi không thể sử dụng np.pad. Ví dụ, tôi muốn pad a với số không sao cho hình dạng của nó khớp với b. Lý do tại sao tôi muốn làm điều này là vì vậy tôi có thể làm:python làm thế nào để pad mảng numpy với số không

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

Cách duy nhất tôi có thể nghĩ để làm điều này là phụ thêm, tuy nhiên điều này có vẻ khá xấu xí. là có một giải pháp sạch hơn có thể sử dụng b.shape?

Chỉnh sửa, Cảm ơn bạn đã trả lời MSeiferts. Tôi phải làm sạch nó lên một chút, và đây là những gì tôi nhận:

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

Tôi có thể đề xuất cho bạn cách để làm điều đó mà không cần đệm không? – purpletentacle

Trả lời

44

Rất đơn giản, bạn tạo một mảng chứa số không sử dụng hình tham khảo:

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 

và sau đó chèn mảng nơi bạn cần nó:

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

và voila bạn đã đệm nó:

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

Bạn cũng có thể làm cho nó một chút tổng quát hơn nếu bạn xác định nơi yếu tố phía trên bên trái của bạn nên được chèn

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

nhưng sau đó hãy cẩn thận rằng bạn không có offsets lớn hơn mức cho phép. Ví dụ: x_offset = 2, điều này sẽ không thành công.


Nếu bạn có số thứ tự kích thước bạn có thể xác định danh sách các lát để chèn mảng ban đầu. Tôi đã tìm thấy nó thú vị để chơi xung quanh một chút và tạo ra một chức năng padding có thể pad (với bù đắp) một mảng hình arbitary miễn là mảng và tham chiếu có cùng một số kích thước và bù đắp không quá lớn.

trường hợp
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 

Và một số kiểm tra:

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) 
+0

ah rất đẹp. Điều này có thể được tổng quát thành mảng 1d hoặc bất kỳ mảng n d nào không? – user2015487

+0

@ user2015487 - Bạn có nghĩa là một hàm chấp nhận kích thước đơn phương hoặc chỉ giống nhau cho MỘT số thứ nguyên khác? – MSeifert

4

Tôi hiểu rằng vấn đề chính của bạn là bạn cần phải tính toán d=b-a nhưng mảng của bạn có kích cỡ khác nhau. Không cần cho một trung gian đệm c

Bạn có thể giải quyết này mà không có padding:

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 

Output:

[[ 2. 2. 2. 2. 2. 3.] 
[ 2. 2. 2. 2. 2. 3.] 
[ 2. 2. 2. 2. 2. 3.] 
[ 3. 3. 3. 3. 3. 3.]] 
+0

Đúng, đối với trường hợp cụ thể của mình, ông không nhất thiết cần phải pad nhưng đó là một trong số ít hoạt động số học nơi đệm và cách tiếp cận của bạn là tương đương. Tuy nhiên câu trả lời tốt đẹp! – MSeifert

20

NumPy 1,7 (khi np.pad đã được bổ sung) là khá cũ bây giờ (nó đã được phát hành vào năm 2013) vì vậy mặc dù câu hỏi được hỏi về cách mà không có chức năng đó, tôi nghĩ có thể hữu ích khi biết cách có thể đạt được bằng cách sử dụng np.pad.

Nó thực sự khá đơn giản:

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

Trong trường hợp này tôi sử dụng mà 0 là giá trị mặc định cho mode='constant'. Nhưng nó cũng có thể được xác định bằng cách đi qua nó trong một cách rõ ràng:

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

Chỉ trong trường hợp đối số thứ hai ([(0, 1), (0, 1)]) có vẻ khó hiểu: Mỗi mục trong danh sách (trong trường hợp này tuple) tương ứng với một kích thước và mục trong đó đại diện cho đệm trước (phần tử đầu tiên) và sau (phần tử thứ hai). Vì vậy:

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

Trong trường hợp này đệm cho trục thứ nhất và thứ hai là giống hệt nhau, vì vậy người ta cũng có thể chỉ cần vượt qua trong 2-tuple:

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

Trong trường hợp đệm trước và sau là một giống hệt thậm chí có thể bỏ qua các tuple (không áp dụng trong trường hợp này mặc dù):

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

Hoặc nếu đệm trước và sau là giống hệt nhau nhưng khác nhau cho các trục, bạn cũng có thể bỏ qua đối số thứ hai trong các bộ nội:

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

Tuy nhiên tôi có xu hướng thích để luôn luôn sử dụng một rõ ràng, bởi vì nó chỉ là để dễ mắc sai lầm (khi NumPys mong đợi khác với ý định của bạn):

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

đây NumPy nghĩ rằng bạn muốn pad tất cả trục với 1 phần tử trước và 2 phần tử sau mỗi trục! Ngay cả khi bạn định dùng nó với 1 phần tử ở trục 1 và 2 phần tử cho trục 2.

Tôi đã sử dụng danh sách bộ đệm cho ghi chú, lưu ý rằng đây chỉ là "quy ước của tôi", bạn cũng có thể sử dụng danh sách danh sách hoặc bộ dữ liệu hoặc thậm chí là các mảng. NumPy chỉ kiểm tra độ dài của đối số (hoặc nếu nó không có chiều dài) và độ dài của mỗi mục (hoặc nếu nó có chiều dài)!

0

Trong trường hợp bạn cần phải thêm một hàng rào của 1s để một mảng:

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

Cảm ơn bạn.

Các vấn đề liên quan