2008-12-15 39 views
112

Làm thế nào tôi có thể xây dựng một mảng numpy ra khỏi một đối tượng máy phát điện?Làm thế nào để xây dựng một mảng numpy từ một máy phát điện?

Hãy để tôi minh họa cho vấn đề:

>>> import numpy 
>>> def gimme(): 
... for x in xrange(10): 
...  yield x 
... 
>>> gimme() 
<generator object at 0x28a1758> 
>>> list(gimme()) 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>> numpy.array(xrange(10)) 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
>>> numpy.array(gimme()) 
array(<generator object at 0x28a1758>, dtype=object) 
>>> numpy.array(list(gimme())) 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

Trong trường hợp này, gimme() là các máy phát điện có đầu ra tôi muốn biến thành một mảng. Tuy nhiên, các nhà xây dựng mảng không lặp qua máy phát điện, nó chỉ đơn giản là lưu trữ các máy phát điện chính nó. Các hành vi tôi mong muốn là từ numpy.array (danh sách (gimme())), nhưng tôi không muốn trả tiền chi phí bộ nhớ của việc có danh sách trung gian và mảng cuối cùng trong bộ nhớ cùng một lúc. Có cách nào hiệu quả hơn không gian?

+5

Đây là một vấn đề thú vị. Tôi đã vượt qua điều này bằng cách 'từ nhập khẩu gumpy *; in bất kỳ (False cho i trong phạm vi (1)) '- mà bóng được xây dựng trong [' bất kỳ() '] (http://docs.python.org/library/functions.html#any) và sản xuất ngược lại kết quả (như tôi biết bây giờ). – moooeeeep

+4

@moooeeeep thật khủng khiếp. nếu 'numpy' không thể (hoặc không muốn) để xử lý các máy phát điện như Python, ít nhất nó cũng sẽ tăng một ngoại lệ khi nó nhận một trình tạo như một đối số. – max

+1

@max Tôi bước vào cùng một mỏ. Dường như điều này đã được nêu ra [trên danh sách NumPy] (http://thread.gmane.org/gmane.comp.python.numeric.general/47681/focus=47702) (và [trước] (http: //thread.gmane .org/gmane.comp.python.numeric.general/13197)) kết luận rằng điều này sẽ không được thay đổi để tăng ngoại lệ và người ta phải luôn sử dụng các không gian tên. – alexei

Trả lời

93

Các mảng cố định yêu cầu độ dài của chúng được đặt rõ ràng tại thời điểm tạo, không giống như danh sách python. Điều này là cần thiết để không gian cho mỗi mục có thể được phân bổ liên tục trong bộ nhớ. Phân bổ liên tiếp là tính năng chính của mảng numpy: điều này kết hợp với việc triển khai mã gốc cho phép các thao tác trên chúng thực thi nhanh hơn nhiều so với các danh sách thông thường.

Giữ điều này trong tâm trí, nó là về mặt kỹ thuật không thể lấy một đối tượng phát và biến nó thành một mảng trừ khi bạn có:

  1. có thể dự đoán có bao nhiêu yếu tố đó sẽ mang lại khi chạy:

    my_array = numpy.empty(predict_length()) 
    for i, el in enumerate(gimme()): my_array[i] = el 
    
  2. sẵn sàng để lưu trữ phần tử của nó trong một danh sách trung gian:

    my_array = numpy.array(list(gimme())) 
    
  3. có thể làm cho hai máy phát điện giống hệt nhau, chạy qua người đầu tiên tìm ra tổng chiều dài, khởi tạo mảng, và sau đó chạy qua các máy phát điện một lần nữa để tìm từng yếu tố:

    length = sum(1 for el in gimme()) 
    my_array = numpy.empty(length) 
    for i, el in enumerate(gimme()): my_array[i] = el 
    

có lẽ những gì bạn đang tìm kiếm. là không gian không hiệu quả, và là thời gian không hiệu quả (bạn phải đi qua máy phát điện hai lần).

+7

'array.array' nội trang là một danh sách không liên kết liền kề, và bạn có thể chỉ đơn giản là' array.array ('f', generator) '. Để nói rằng nó không thể là sai lầm. Nó chỉ là phân bổ động. – Cuadue

+0

Tại sao numpy.array không thực hiện phân bổ bộ nhớ giống như mảng builtin array.array, như Cuadue nói. Tradeof là gì? Tôi hỏi vì có bộ nhớ phân bổ liền kề trong cả hai ví dụ. Hay không? – jgomo3

+2

numpy giả định kích thước mảng của nó không thay đổi. Nó phụ thuộc rất nhiều vào các khung nhìn khác nhau của cùng một bộ nhớ, do đó, cho phép các mảng được mở rộng và phân bổ lại sẽ yêu cầu một lớp bổ sung của indirection để cho phép các khung nhìn, ví dụ. – joeln

150

Một google đằng sau kết quả ngăn xếp ngăn xếp này, tôi thấy rằng có numpy.fromiter(data, dtype, count). Mặc định count=-1 lấy tất cả các phần tử từ lần lặp lại. Yêu cầu phải có dtype để được đặt rõ ràng.Trong trường hợp của tôi, điều này làm việc:

numpy.fromiter(something.generate(from_this_input), float)

+0

bạn sẽ áp dụng điều này cho câu hỏi như thế nào? 'numpy.fromiter (gimme(), float, count = -1)' không hoạt động. “Cái gì” có nghĩa là gì? –

+0

something.generate chỉ là tên của máy phát điện –

+1

@ Matthias009 'numpy.fromiter (gimme(), float, count = -1)' hoạt động cho tôi. – moooeeeep

5

Hơi tiếp tuyến, nhưng nếu máy phát điện của bạn là một danh sách hiểu, bạn có thể sử dụng numpy.where để hiệu quả hơn có được kết quả của bạn (tôi phát hiện ra điều này trong mã của riêng tôi sau khi nhìn thấy bài này)

3

Trong khi bạn có thể tạo một mảng 1D từ một máy phát điện với numpy.fromiter(), bạn có thể tạo một mảng NĐ từ một máy phát điện với numpy.stack:

>>> mygen = (np.ones((5, 3)) for _ in range(10)) 
>>> x = numpy.stack(mygen) 
>>> x.shape 
(10, 5, 3) 

Nó cũng w orks cho mảng 1D:

>>> numpy.stack(2*i for i in range(10)) 
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]) 

Lưu ý rằng numpy.stack được nội tiêu thụ máy phát điện và tạo ra một danh sách trung gian với arrays = [asanyarray(arr) for arr in arrays]. Việc thực hiện có thể được tìm thấy here.

+0

Đây là một giải pháp gọn gàng, cảm ơn bạn đã chỉ ra. Nhưng nó có vẻ khá chậm hơn một chút (trong ứng dụng của tôi) hơn là sử dụng 'np.array (tuple (mygen))'. Đây là kết quả kiểm tra: '% timeit np.stack (hoán vị (khoảng (10), 7)) 1 vòng lặp, tốt nhất là 3: 1,9 s trên mỗi vòng lặp' so với'% timeit np.array (tuple (hoán vị (phạm vi) 10), 7))) 1 vòng lặp, tốt nhất là 3: 427 ms trên mỗi vòng lặp – Bill

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