2014-10-15 15 views
7

Có cách nào tốt hơn trong numpy để xếp mảng một số nguyên không? Đây được công việc làm, nhưng thiếu uyển chuyển và không dễ dàng khái quát đến n-kích thước:numpy.tile số không phải là số nguyên

import numpy as np 
arr = np.arange(6).reshape((2, 3)) 
desired_shape = (5, 8) 
reps = tuple([x // y for x, y in zip(desired_shape, arr.shape)]) 
left = tuple([x % y for x, y in zip(desired_shape, arr.shape)]) 
tmp = np.tile(arr, reps) 
tmp = np.r_[tmp, tmp[slice(left[0]), :]] 
tmp = np.c_[tmp, tmp[:, slice(left[1])]] 

sản lượng này:

array([[0, 1, 2, 0, 1, 2, 0, 1], 
     [3, 4, 5, 3, 4, 5, 3, 4], 
     [0, 1, 2, 0, 1, 2, 0, 1], 
     [3, 4, 5, 3, 4, 5, 3, 4], 
     [0, 1, 2, 0, 1, 2, 0, 1]]) 

EDIT: Hiệu suất kết quả

Một số thử nghiệm của ba câu trả lời đã được tổng quát thành n-kích thước. Những định nghĩa đã được đặt trong một tập tin newtile.py:

import numpy as np 

def tile_pad(a, dims): 
    return np.pad(a, tuple((0, i) for i in (np.array(dims) - a.shape)), 
        mode='wrap') 

def tile_meshgrid(a, dims): 
    return a[np.meshgrid(*[np.arange(j) % k for j, k in zip(dims, a.shape)], 
         sparse=True, indexing='ij')] 

def tile_rav_mult_idx(a, dims): 
    return a.flat[np.ravel_multi_index(np.indices(dims), a.shape, mode='wrap')] 

Sau đây là các dòng bash:

python -m timeit -s 'import numpy as np' 'import newtile' 'newtile.tile_pad(np.arange(30).reshape(2, 3, 5), (3, 5, 7))' 
python -m timeit -s 'import numpy as np' 'import newtile' 'newtile.tile_meshgrid(np.arange(30).reshape(2, 3, 5), (3, 5, 7))' 
python -m timeit -s 'import numpy as np' 'import newtile' 'newtile.tile_rav_mult_idx(np.arange(30).reshape(2, 3, 5), (3, 5, 7))' 

python -m timeit -s 'import numpy as np' 'import newtile' 'newtile.tile_pad(np.arange(2310).reshape(2, 3, 5, 7, 11), (13, 17, 19, 23, 29))' 
python -m timeit -s 'import numpy as np' 'import newtile' 'newtile.tile_meshgrid(np.arange(2310).reshape(2, 3, 5, 7, 11), (13, 17, 19, 23, 29))' 
python -m timeit -s 'import numpy as np' 'import newtile' 'newtile.tile_rav_mult_idx(np.arange(2310).reshape(2, 3, 5, 7, 11), (13, 17, 19, 23, 29))' 

Sau đây là các kết quả với mảng nhỏ (2 x 3 x 5):

pad:    10000 loops, best of 3: 106 usec per loop 
meshgrid:   10000 loops, best of 3: 56.4 usec per loop 
ravel_multi_index: 10000 loops, best of 3: 50.2 usec per loop 

Đây là kết quả có mảng lớn hơn (2 x 3 x 5 x 7 x 11):

pad:    10 loops, best of 3: 25.2 msec per loop 
meshgrid:   10 loops, best of 3: 300 msec per loop 
ravel_multi_index: 10 loops, best of 3: 218 msec per loop 

Vì vậy, phương pháp sử dụng np.pad có lẽ là lựa chọn hiệu quả nhất.

+0

hành vi sẽ như thế nào khi sử dụng 'np.tile()' với số nguyên không? –

+1

@SaulloCastro: Có lẽ tiêu đề của tôi hơi gây hiểu nhầm. Theo ý kiến ​​của tôi 'np.tile' nên * không * lấy các đối số phi số nguyên thành' reps'. Những gì tôi muốn đạt được là * tương tự * với những gì sẽ xảy ra nếu 'np.tile' thực hiện các đối số không phải số nguyên cho' reps' ** và ** nếu số nguyên không được truyền đạt được số nguyên của hàng/cột/v.v. trong mảng đầu ra. Ví dụ tương tự gần nhất mà tôi biết là đối số 'length.out' đối với hàm' rep() 'trong ngôn ngữ' R'. – drammock

Trả lời

2

Một giải pháp mà thậm chí còn ngắn gọn hơn:

arr = np.arange(6).reshape((2, 3)) 
desired_shape = np.array((5, 8)) 

pads = tuple((0, i) for i in (desired_shape-arr.shape)) 
# pads = ((0, add_rows), (0, add_columns), ...) 
np.pad(arr, pads, mode="wrap") 

nhưng nó là chậm hơn cho mảng nhỏ (nhanh hơn nhiều đối với những người lớn mặc dù). Kỳ lạ, np.pad sẽ không chấp nhận np.array cho miếng đệm.

0

Không chắc chắn cho kích thước n, nhưng bạn có thể xem xét sử dụng hstackvstack.

arr = np.arange(6).reshape((2, 3)) 

nx, ny = shape(arr) 
Nx, Ny = 5, 8 # These are the new shapes 
iX, iY = Nx//nx+1, Ny//ny+1 

result = vstack(tuple([ hstack(tuple([arr]*iX))[:, :Nx] ]*iY))[:Ny, : ] 

dstack, nhưng tôi nghi ngờ liệu điều đó có hiệu quả hay không. Không hoàn toàn chắc chắn về 3 và cao hơn dimentions.

2

Dưới đây là một phương pháp khá ngắn gọn:

In [57]: a 
Out[57]: 
array([[0, 1, 2], 
     [3, 4, 5]]) 

In [58]: old = a.shape 

In [59]: new = (5, 8) 

In [60]: a[(np.arange(new[0]) % old[0])[:,None], np.arange(new[1]) % old[1]] 
Out[60]: 
array([[0, 1, 2, 0, 1, 2, 0, 1], 
     [3, 4, 5, 3, 4, 5, 3, 4], 
     [0, 1, 2, 0, 1, 2, 0, 1], 
     [3, 4, 5, 3, 4, 5, 3, 4], 
     [0, 1, 2, 0, 1, 2, 0, 1]]) 

Dưới đây là một sự tổng quát n chiều:

def rep_shape(a, shape): 
    indices = np.meshgrid(*[np.arange(k) % j for j, k in zip(a.shape, shape)], 
          sparse=True, indexing='ij') 
    return a[indices] 

Ví dụ:

In [89]: a 
Out[89]: 
array([[0, 1, 2], 
     [3, 4, 5]]) 

In [90]: rep_shape(a, (5, 8)) 
Out[90]: 
array([[0, 1, 2, 0, 1, 2, 0, 1], 
     [3, 4, 5, 3, 4, 5, 3, 4], 
     [0, 1, 2, 0, 1, 2, 0, 1], 
     [3, 4, 5, 3, 4, 5, 3, 4], 
     [0, 1, 2, 0, 1, 2, 0, 1]]) 

In [91]: rep_shape(a, (4, 2)) 
Out[91]: 
array([[0, 1], 
     [3, 4], 
     [0, 1], 
     [3, 4]]) 

In [92]: b = np.arange(24).reshape(2,3,4) 

In [93]: b 
Out[93]: 
array([[[ 0, 1, 2, 3], 
     [ 4, 5, 6, 7], 
     [ 8, 9, 10, 11]], 

     [[12, 13, 14, 15], 
     [16, 17, 18, 19], 
     [20, 21, 22, 23]]]) 

In [94]: rep_shape(b, (3,4,5)) 
Out[94]: 
array([[[ 0, 1, 2, 3, 0], 
     [ 4, 5, 6, 7, 4], 
     [ 8, 9, 10, 11, 8], 
     [ 0, 1, 2, 3, 0]], 

     [[12, 13, 14, 15, 12], 
     [16, 17, 18, 19, 16], 
     [20, 21, 22, 23, 20], 
     [12, 13, 14, 15, 12]], 

     [[ 0, 1, 2, 3, 0], 
     [ 4, 5, 6, 7, 4], 
     [ 8, 9, 10, 11, 8], 
     [ 0, 1, 2, 3, 0]]]) 

Đây là ví dụ đầu tiên hoạt động ...

Ý tưởng là sử dụng mảng để lập chỉ mục a. Hãy nhìn vào np.arange(new[0] % old[0]):

In [61]: np.arange(new[0]) % old[0] 
Out[61]: array([0, 1, 0, 1, 0]) 

Mỗi giá trị trong mảng cung cấp cho các hàng a để sử dụng trong kết quả. Similary,

In [62]: np.arange(new[1]) % old[1] 
Out[62]: array([0, 1, 2, 0, 1, 2, 0, 1]) 

cung cấp các cột a để sử dụng trong kết quả.Đối với những mảng chỉ số để tạo ra một kết quả 2-d, chúng ta phải định hình lại là người đầu tiên vào một cột:

In [63]: (np.arange(new[0]) % old[0])[:,None] 
Out[63]: 
array([[0], 
     [1], 
     [0], 
     [1], 
     [0]]) 

Khi mảng được sử dụng như các chỉ số, họ phát sóng. Đây là những gì các chỉ số phát sóng như sau:

n [65]: i, j = np.broadcast_arrays((np.arange(new[0]) % old[0])[:,None], np.arange(new[1]) % old[1]) 

In [66]: i 
Out[66]: 
array([[0, 0, 0, 0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1, 1, 1, 1], 
     [0, 0, 0, 0, 0, 0, 0, 0], 
     [1, 1, 1, 1, 1, 1, 1, 1], 
     [0, 0, 0, 0, 0, 0, 0, 0]]) 

In [67]: j 
Out[67]: 
array([[0, 1, 2, 0, 1, 2, 0, 1], 
     [0, 1, 2, 0, 1, 2, 0, 1], 
     [0, 1, 2, 0, 1, 2, 0, 1], 
     [0, 1, 2, 0, 1, 2, 0, 1], 
     [0, 1, 2, 0, 1, 2, 0, 1]]) 

Đây là những mảng chỉ số mà chúng ta cần để tạo ra các mảng với hình dạng (5, 8):

In [68]: a[i,j] 
Out[68]: 
array([[0, 1, 2, 0, 1, 2, 0, 1], 
     [3, 4, 5, 3, 4, 5, 3, 4], 
     [0, 1, 2, 0, 1, 2, 0, 1], 
     [3, 4, 5, 3, 4, 5, 3, 4], 
     [0, 1, 2, 0, 1, 2, 0, 1]]) 

Khi mảng chỉ số được cho là trong ví dụ ngay từ đầu (tức là sử dụng (np.arange(new[0]) % old[0])[:,None] trong khe chỉ mục đầu tiên), không thực sự tạo ra các mảng chỉ mục này trong bộ nhớ như tôi đã làm với ij. ij hiển thị nội dung hiệu quả khi phát sóng diễn ra.

Chức năng rep_shape thực hiện tương tự, sử dụng np.meshgrid để tạo các mảng chỉ mục cho từng "vị trí" với hình dạng chính xác để phát sóng.

2

Có lẽ không phải là rất hiệu quả nhưng rất súc tích:

arr = np.arange(6).reshape((2, 3)) 
desired_shape = (5, 8) 

arr.flat[np.ravel_multi_index(np.indices(desired_shape), arr.shape, mode='wrap')] 
+0

Tuyệt. Tổng quát về n-kích thước quá, như xa như tôi có thể nói: thử nghiệm với 'arr = np.arange (30) .reshape ((2, 3, 5))' và 'mong_shape = (5, 8, 13)' – drammock

+0

Điều này làm việc tuyệt vời. Một nhược điểm tiềm năng là, trong trường hợp n-chiều, 'np.indices (mong_shape)' tạo ra một mảng tạm thời với hình dạng '(n,) + desired_shape' (ví dụ: (3, 5, 8, 13) khi' mong muốn_shape' là (5, 8, 13)). Nhưng đó không phải là vấn đề nếu các mảng nhỏ. –

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