2012-03-05 35 views
5

(Trong bài này, chúng ta hãy np được viết tắt cho numpy.)liệt kê numpy.ndarray trên một tập con thích hợp của các tham số?

Giả sử a là một (n   +   k) & # x2011; chiều đối tượng np.ndarray, đối với một số nguyên n   >   1 và k   >   1. (IOW, n   +   k   >   3 là giá trị a.ndim). Tôi muốn liệt kê a qua số thứ tự n đầu tiên của mình; điều này có nghĩa rằng, tại mỗi lần lặp, các điều tra viên/iterator tạo ra một cặp mà yếu tố đầu tiên là một tuple ii của n chỉ số, và yếu tố thứ hai là k & # x2011; chiều phụ ndarray tại a[ii].

Cấp, nó không phải là khó khăn để mã hóa một chức năng để làm điều này (trong thực tế, tôi đưa ra một ví dụ về một hàm như dưới đây), nhưng tôi muốn biết điều này:

không numpy cung cấp bất kỳ đặc biệt cú pháp hoặc hàm để thực hiện kiểu liệt kê "một phần" này?

(Thông thường, khi tôi muốn để lặp qua một đối tượng đa chiều np.ndarray, tôi sử dụng np.ndenumerate, nhưng nó sẽ không giúp đỡ ở đây, bởi vì (như xa như tôi có thể nói) np.ndenumerate sẽ lặp qua tất cả n   +   k kích thước)

Giả sử rằng câu trả lời cho câu hỏi trên là có, thì có này theo dõi:.

trường hợp các tham số n để lặp lại không tiếp giáp?

(Trong trường hợp này, yếu tố đầu tiên của cặp trở ở mỗi lần lặp của các điều tra viên/iterator sẽ là một tuple của r   >   n yếu tố, một số trong đó sẽ là một giá trị đặc biệt biểu thị "tất cả", ví dụ: slice(None); phần tử thứ hai của cặp này vẫn sẽ là một số ndarray dài k.)

Cảm ơn!


Mã bên dưới hy vọng làm rõ đặc tả vấn đề. Chức năng partial_enumerate làm những gì tôi muốn làm bằng cách sử dụng bất kỳ cấu trúc đặc biệt numpy nào có sẵn cho mục đích này.Theo định nghĩa của partial_enumerate là một ví dụ đơn giản đối với trường hợp n   =   k   =   2.

import numpy as np 
import itertools as it 
def partial_enumerate(nda, n): 
    """Enumerate over the first N dimensions of the numpy.ndarray NDA. 

    Returns an iterator of pairs. The first element of each pair is a tuple 
    of N integers, corresponding to a partial index I into NDA; the second element 
    is the subarray of NDA at I. 
    """ 

    # ERROR CHECKING & HANDLING OMITTED 
    for ii in it.product(*[range(d) for d in nda.shape[:n]]): 
    yield ii, nda[ii] 

a = np.zeros((2, 3, 4, 5)) 
for ii, vv in partial_enumerate(a, 2): 
    print ii, vv.shape 

Mỗi dòng của đầu ra là một "cặp tuples", nơi mà các tuple đầu tiên đại diện cho bộ phận một phần của các tọa độ n trong a và cột thứ hai biểu thị hình dạng của một phụ đề k & # x2011; chiều của a tại các tọa độ từng phần đó; (Giá trị của cặp thứ hai này là như nhau cho tất cả các dòng, như mong đợi từ đặn của mảng):

(0, 0) (4, 5) 
(0, 1) (4, 5) 
(0, 2) (4, 5) 
(1, 0) (4, 5) 
(1, 1) (4, 5) 
(1, 2) (4, 5) 

Ngược lại, lặp lại trên np.ndenumerate(a) trong trường hợp này sẽ cho kết quả trong a.size lần lặp lại, mỗi quý khách đến thăm một cá nhân ô của a.

+1

"trường hợp kích thước để lặp lại không tiếp giáp?" Tôi không chắc chắn rằng có thể với một mảng numpy tinh khiết. Toàn bộ mảng được lưu trữ trong một khối bộ nhớ liền kề, không giống như một danh sách python chuẩn. Ví dụ, bạn có nghĩa là một mảng 2D với kết quả của '[row.shape cho hàng trong một]' = '[1,2,1,3, ...]'? – Hooked

+0

"Trong trường hợp này, phần tử đầu tiên của cặp được trả về tại mỗi lần lặp bởi toán tử/bộ lặp sẽ là một bộ gồm các phần tử r> n, một số trong đó sẽ là một giá trị đặc biệt biểu thị" tất cả ", ví dụ slice (None); phần tử thứ hai của cặp này vẫn sẽ là một độ dài của độ dài k. " Điều này không có ý nghĩa với tôi, bởi vì nó tạo ra một thành ngữ không nhất quán. Thay vì bao gồm các chỉ mục mục duy nhất, nó sẽ bao gồm một kết hợp của các chỉ mục đơn và chuỗi các chỉ mục. Do đó, nó sẽ không còn là sự đánh dấu giữa các chỉ số và các mảng phụ; một chỉ mục có thể tham chiếu đến nhiều mảng phụ. – senderle

+0

Tôi tin rằng điều này sẽ dẫn đến một độ dài độ dài k + j trong đó j là số chuỗi (tức là các mục không phải mục đơn) trong bộ lập chỉ mục. – senderle

Trả lời

4

Tôi nghĩ bạn đang tìm kiếm hàm ndindex trong numpy. Chỉ mất một lát các mảng con mà bạn muốn:

from numpy import * 

# Create the array 
A = zeros((2,3,4,5)) 

# Identify the subindex you're looking for 
idx = ndindex(A.shape[:2]) 

# Iterate through the array 
[(x, A[x].shape) for x in idx] 

này cho kết quả mong đợi:

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

Bạn có thể sử dụng các quy tắc phát sóng NumPy để tạo ra một sản phẩm Descartes. Hàm numpy.ix_ tạo danh sách các mảng phù hợp. Nó tương đương với dưới đây:

>>> def pseudo_ix_gen(*arrays): 
...  base_shape = [1 for arr in arrays] 
...  for dim, arr in enumerate(arrays): 
...   shape = base_shape[:] 
...   shape[dim] = len(arr) 
...   yield numpy.array(arr).reshape(shape) 
... 
>>> def pseudo_ix_(*arrays): 
...  return list(pseudo_ix_gen(*arrays)) 

Hoặc, ngắn gọn hơn:

>>> def pseudo_ix_(*arrays): 
...  shapes = numpy.diagflat([len(a) - 1 for a in arrays]) + 1 
...  return [numpy.array(a).reshape(s) for a, s in zip(arrays, shapes)] 

Kết quả là một danh sách các mảng broadcastable:

>>> numpy.ix_(*[[2, 4], [1, 3], [0, 2]]) 
[array([[[2]], 

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

Hãy so sánh này để kết quả của numpy.ogrid:

>>> numpy.ogrid[0:2, 0:2, 0:2] 
[array([[[0]], 

     [[1]]]), array([[[0], 
     [1]]]), array([[[0, 1]]])] 

Như bạn có thể thấy, nó giống nhau, nhưng numpy.ix_ cho phép bạn sử dụng các chỉ mục không liên tiếp. Bây giờ khi chúng ta áp dụng các quy tắc phát sóng NumPy, chúng tôi có được một sản phẩm Descartes:

>>> list(numpy.broadcast(*numpy.ix_(*[[2, 4], [1, 3], [0, 2]]))) 
[(2, 1, 0), (2, 1, 2), (2, 3, 0), (2, 3, 2), 
(4, 1, 0), (4, 1, 2), (4, 3, 0), (4, 3, 2)] 

Nếu, thay vì đi qua các kết quả của numpy.ix_-numpy.broadcast, chúng ta sử dụng nó để chỉ số một mảng, chúng ta có được điều này:

>>> a = numpy.arange(6 ** 4).reshape((6, 6, 6, 6)) 
>>> a[numpy.ix_(*[[2, 4], [1, 3], [0, 2]])] 
array([[[[468, 469, 470, 471, 472, 473], 
     [480, 481, 482, 483, 484, 485]], 

     [[540, 541, 542, 543, 544, 545], 
     [552, 553, 554, 555, 556, 557]]], 


     [[[900, 901, 902, 903, 904, 905], 
     [912, 913, 914, 915, 916, 917]], 

     [[972, 973, 974, 975, 976, 977], 
     [984, 985, 986, 987, 988, 989]]]]) 

Tuy nhiên, biểu tượng báo trước. mảng Broadcastable có ích cho việc lập chỉ mục, nhưng nếu bạn có nghĩa là muốn liệt kê các giá trị, bạn có thể được tốt hơn bằng cách sử dụng itertools.product:

>>> %timeit list(itertools.product(range(5), repeat=5)) 
10000 loops, best of 3: 196 us per loop 
>>> %timeit list(numpy.broadcast(*numpy.ix_(*([range(5)] * 5)))) 
100 loops, best of 3: 2.74 ms per loop 

Vì vậy, nếu bạn đang kết hợp một vòng lặp for dù sao, sau đó itertools.product sẽ có khả năng được nhanh hơn.Tuy nhiên, bạn có thể sử dụng các phương pháp trên để nhận được một số cấu trúc dữ liệu tương tự ở dạng gọn gàng thuần túy:

>> pgrid_idx = numpy.ix_(*[[2, 4], [1, 3], [0, 2]]) 
>>> sub_indices = numpy.rec.fromarrays(numpy.indices((6, 6, 6))) 
>>> a[pgrid_idx].reshape((8, 6)) 
array([[468, 469, 470, 471, 472, 473], 
     [480, 481, 482, 483, 484, 485], 
     [540, 541, 542, 543, 544, 545], 
     [552, 553, 554, 555, 556, 557], 
     [900, 901, 902, 903, 904, 905], 
     [912, 913, 914, 915, 916, 917], 
     [972, 973, 974, 975, 976, 977], 
     [984, 985, 986, 987, 988, 989]]) 
>>> sub_indices[pgrid_idx].reshape((8,)) 
rec.array([(2, 1, 0), (2, 1, 2), (2, 3, 0), (2, 3, 2), 
      (4, 1, 0), (4, 1, 2), (4, 3, 0), (4, 3, 2)], 
      dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8')]) 
+2

Tôi tin rằng 'product_grid' của bạn giống với' numpy.ix_'. –

+1

@Bago, không có gì giống như phát minh lại bánh xe, phải không? – senderle

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