2015-04-29 16 views
7

Sau đây tạo ra một mảng NumPy C tiếp giáp:Cách rẻ nhất để có được một mảng numpy vào thứ tự tiếp giáp C?

import numpy 

a = numpy.ones((1024,1024,5)) 

Bây giờ nếu tôi cắt nó, kết quả có thể không còn được như vậy. Ví dụ:

bn = a[:, :, n] 

với n từ 0 đến 4. Vấn đề của tôi là tôi cần bn là C tiếp giáp, và tôi cần phải làm điều này cho nhiều trường hợp một. Tôi chỉ cần mỗi bn một lần, và muốn tránh làm

bn = bn.copy(order='C') 

Tôi cũng không muốn viết lại mã của tôi như vậy mà

a = numpy.ones((5,1024,1024)) 

Có một cách nhanh hơn, rẻ hơn để có được bn hơn làm Bản sao chép?

Bối cảnh:

Tôi muốn băm từng miếng mỗi a, sử dụng

import hashlib 

hashlib.sha1(a[:, :, n]).hexdigest() 

Thật không may, điều này sẽ ném một ValueError, phàn nàn về đơn đặt hàng. Vì vậy, nếu có một cách nhanh chóng để có được băm tôi muốn, tôi cũng sẽ sử dụng nó.

+0

Trên một lưu ý liên quan, tôi chỉ biết về hành vi của hashlib bằng cách thực hiện một _lot_ gỡ lỗi cho đến khi tôi tìm thấy nơi ngoại lệ mà thực sự đến từ đâu. Không nên các tài liệu python đề cập đến điều này? –

Trả lời

4

Khi mọi thứ được thực hiện, bất kỳ nỗ lực nào để ép buộc lát cắt bn đến C thứ tự tiếp giáp sẽ tạo bản sao.

Nếu bạn không muốn thay đổi hình dạng bạn đang bắt đầu với (và không cần a tự theo thứ tự C), một trong những giải pháp khả thi là bắt đầu với mảng a để Fortran:

>>> a = numpy.ones((1024, 1024, 5), order='f') 

các lát cũng là sau đó F-liền kề:

>>> bn = a[:, :, 0] 
>>> bn.flags 
    C_CONTIGUOUS : False 
    F_CONTIGUOUS : True 
    OWNDATA : False 
    ... 

này có nghĩa là chuyển vị của slice bn sẽ được theo thứ tự C và transposing không không tạo một bản sao:

>>> bn.T.flags 
    C_CONTIGUOUS : True 
    F_CONTIGUOUS : False 
    OWNDATA : False 
    ... 

Và sau đó bạn có thể băm lát:

>>> hashlib.sha1(bn.T).hexdigest() 
'01dfa447dafe16b9a2972ce05c79410e6a96840e' 
+3

Điều này dường như với tôi giống như đường dẫn chính xác đến một giải pháp, nhưng bạn đang thay đổi thứ tự của hai trục kia khi chuyển đổi chế độ xem, không đẹp. Một cái gì đó như 'a = numpy.ones ((5, 1024, 1024)). Transpose (1, 2, 0)' cung cấp cho bạn một mảng không phải là C và Fortran tiếp giáp, nhưng nó tạo ra các C-tiếp giáp lát khi được lập chỉ mục dọc theo kích thước cuối cùng. – Jaime

5

Để buộc một mảng NumPy x là C tiếp giáp, mà không làm cho các bản sao không cần thiết khi nó đã như vậy để bắt đầu với, bạn nên sử dụng,

x = numpy.asarray(x, order='C') 

Lưu ý, rằng nếu mảng này là không C- tiếp giáp, nó có thể sẽ tương tự về mặt hiệu quả với x.copy(order='C'). Tôi không nghĩ rằng có một cách xung quanh nó. Bạn không thể tổ chức lại sự liên kết của một mảng trong bộ nhớ bằng cách tạo bản sao dữ liệu cho một vị trí mới.

Viết lại mã của bạn để nó sử dụng chỉ mục được cắt lát trước, như trong numpy.ones((5,1024,1024)) có vẻ là cách hợp lý duy nhất để tối ưu hóa điều này.

4

Đây là một hoạt động tiêu chuẩn khi interfacing NumPy với C. Có một cái nhìn tại numpy.ascontiguousarray

x=numpy.ascontiguousarray(x)

là cách thích hợp để đối phó với nó.

Sử dụng numpy.asfortranarray nếu bạn cần đặt hàng trước.

Như đã đề cập, chức năng sẽ sao chép nếu cần. Vì vậy, không có cách nào xung quanh nó. Bạn có thể thử rollaxis trước khi thao tác, chẳng hạn như trục ngắn là trục đầu tiên. Điều này cung cấp cho bạn chế độ xem trên mảng

In [2]: A=np.random.rand(1024,1024,5) 
In [3]: B=np.rollaxis(A,2) 
In [4]: B.shape 
Out[4]: (5, 1024, 1024) 
In [5]: B.flags 
Out[5]: 
    C_CONTIGUOUS : False 
    F_CONTIGUOUS : False 
    OWNDATA : False 
    WRITEABLE : True 
    ALIGNED : True 
    UPDATEIFCOPY : False 

In [6]: A.flags 
Out[6]: 
    C_CONTIGUOUS : True 
    F_CONTIGUOUS : False 
    OWNDATA : True 
    WRITEABLE : True 
    ALIGNED : True 
    UPDATEIFCOPY : False 

Vì vậy, rollaxis cũng không giải quyết được điều này.

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