2012-08-23 78 views
8

Tôi muốn thêm hàng ngàn phần tử mảng 4D một cách khôn ngoan và tính toán cho các phần mềm. Một ví dụ đơn giản sử dụng mảng 1D sẽ là:quick numpy addnan

X = array([4,7,89,nan,89,65, nan]) 
Y = array([0,5,4, 9, 8, 100,nan]) 
z = X+Y 
print z = array([4,12,93,9,97,165,nan]) 

Tôi đã viết một đơn giản cho vòng xung quanh này, nhưng nó sẽ mãi mãi - không phải là một giải pháp thông minh. Một giải pháp khác có thể là tạo ra một mảng lớn hơn và sử dụng nút cổ chai nansum nhưng điều này sẽ mất quá nhiều bộ nhớ cho máy tính xách tay của tôi. Tôi cần một số tiền chạy trên 11.000 trường hợp.

Có ai có cách thông minh và nhanh chóng để thực hiện việc này không?

Trả lời

10

Đây là một khả năng:

>>> x = np.array([1, 2, np.nan, 3, np.nan, 4]) 
... y = np.array([1, np.nan, 2, 5, np.nan, 8]) 
>>> x = np.ma.masked_array(np.nan_to_num(x), mask=np.isnan(x) & np.isnan(y)) 
>>> y = np.ma.masked_array(np.nan_to_num(y), mask=x.mask) 
>>> (x+y).filled(np.nan) 
array([ 2., 2., 2., 8., nan, 12.]) 

Khó khăn thực sự là bạn dường như muốn nan để được hiểu là không trừ khi tất cả các giá trị tại một vị trí cụ thể là nan. Điều này có nghĩa là bạn phải nhìn vào cả x và y để xác định những cái nào cần thay thế. Nếu bạn đồng ý với việc thay thế tất cả các giá trị nan, thì bạn có thể chỉ cần thực hiện np.nan_to_num(x) + np.nan_to_num(y).

+0

Mảng mặt nạ là cách để truy cập tại đây nếu việc triển khai gọn gàng của bạn đủ mới để hỗ trợ (tôi không phải là - có thể đã đến lúc nâng cấp) (+1). – mgilson

+0

@mgilson: Heh, có lẽ là thời gian! Tôi nghĩ rằng mảng mặt nạ đã được numpy cho một vài năm nay. – BrenBarn

+0

Vâng máy tính của tôi là một vài tuổi, ^) – mgilson

1

Không chắc chắn cách này sẽ thực hiện, nhưng nó có giá trị một shot :)

def nan_to_zero(array): 
    new_arr = array.copy() 
    new_arr[np.isnan(array)] = 0. 
    return new_arr 

sum(nan_to_zero(arr) for arr in array_generator) 

này không dẫn đến một NaN ở nơi cuối cùng của mảng của bạn mặc dù. Nó là kết quả trong một 0 ...

+2

Numpy đã cung cấp chức năng này trong hàm 'nan_to_num'. – BrenBarn

+0

@mgilson: một danh sách hiểu sau khi loại bỏ các nans. Tôi chưa bao giờ nghĩ về phần hiểu danh sách. Nhưng tôi nghi ngờ điều này giả định một mảng 1D. Không thể xem làm thế nào tôi có thể mã phương pháp này cho một mảng 4D. – Shejo284

+1

@ Shejo284 - Nó thực sự là một biểu thức máy phát điện, nhưng hoạt động tương tự. Tôi không thấy bất kỳ lý do tại sao điều này không thể được sử dụng với mảng 4D mặc dù. Thực sự, mảng 4D chỉ là mảng 1D trong bộ nhớ anyway (Trừ khi bạn thực sự có các đối tượng xem, nhưng nó vẫn nên làm việc với những người là tốt) – mgilson

3

Bạn có thể làm một cái gì đó như:

arr1 = np.array([1.0, 1.0, np.nan, 1.0, 1.0, np.nan]) 
arr2 = np.array([1.0, 1.0, 1.0, 1.0, 1.0, np.nan]) 
flags = np.isnan(arr1) & np.isnan(arr2) 
copy1 = arr1.copy() 
copy2 = arr2.copy() 
copy1[np.isnan(copy1)] = 0.0 
copy2[np.isnan(copy2)] = 0.0 
out = copy1 + copy2 
out[flags] = np.NaN 
print out 
array([ 2., 2., 1., 2., 2., NaN]) 

để tìm các vị trí trong các mảng nơi cả hai đều có một NaN trong chỉ mục đó. Sau đó, về cơ bản những gì @mgilson đề xuất, như làm bản sao và thay thế các NaN s với 0.0, thêm hai mảng lại với nhau, và sau đó thay thế các chỉ mục được gắn cờ ở trên bằng np.NaN.

+0

@mgilson: Tôi đang cố gắng viết một biểu thức máy phát vì nó tiêu thụ ít bộ nhớ hơn nhưng tôi hơi bối rối về cách thức hoạt động của nó khi xử lý các số rất lớn và đọc một tệp netcdf, slice cho slice: cho i in trường hợp: mảng = np.array (netcdfvar [i]) # Sau đó, tổng các lát này tính cho nan không chắc chắn cách trình tạo này trông như thế nào. – Shejo284

+0

@ Shejo284 - Tôi nghĩ bạn đã đăng câu trả lời sai này ;-). Dù sao, tôi không quen thuộc với việc đọc lát từ một tập tin netcdf, nhưng, bạn có thể thử như sau: 'sum (nan_to_zero (np.array (netcdfvar [i])) cho i trong trường hợp)', hoặc như BrenBarn chỉ ra : 'sum (np.nan_to_num (netcdfvar [i]) cho i trong trường hợp)' – mgilson

+0

@mgilson: vâng, bạn nói đúng. Tôi vẫn đang học cách sử dụng trang này. Cảm ơn. Tôi đã thử một số biến thể với sự thành công khác nhau. Giải pháp của bạn là một chút truy cập trực quan. Tôi sẽ kiểm tra nó. – Shejo284

1

tôi thấy một số giải pháp đơn giản hơn:

  • (EDITED) Sử dụng np.ma

    mX = np.ma.masked_array(X, mask=np.isnan(X)) 
    mY = np.ma.masked_array(Y, mask=np.isnan(Y)) 
    mZ = np.ma.masked_array(mX.filled(0) + mY.filled(0), 
             mask=mX.mask * mY.mask) 
    Z = mZ.filled(np.nan) 
    
  • (EDITED) Không được sử dụng np.ma

    mx = np.isnan(x) 
    my = np.isnan(y) 
    z = np.where(mx,0,x) + np.where(my,0,y) 
    z[mx&my] = np.nan 
    
+1

Các giải pháp này không tạo ra kết quả mong muốn. Anh ta muốn các thuật ngữ không phải nan được thêm vào, với nan chỉ xuất hiện trong kết quả nếu các giá trị * tất cả * ở một vị trí cụ thể là nan. Các giải pháp của bạn tạo ra các nút bổ sung ở các vị trí mà chỉ một trong hai vectơ đầu vào có một nan. – BrenBarn

+0

OK, đã sửa. Cảm ơn bạn đã giữ cho tôi trên ngón chân của tôi –

+0

Cũng lưu ý rằng giải pháp cuối cùng của bạn là cái gì mà OP nói rõ ràng rằng anh ấy không muốn làm (tạo một mảng lớn hơn chứa cả hai). Các giải pháp thứ hai trông đẹp, mặc dù. – BrenBarn

3
import numpy as np 
z=np.nansum([X,Y],axis=0) 
+1

Điều này gần như hoạt động. Vấn đề là giải pháp này không tạo ra kết quả mong muốn. Đầu ra phải bao gồm NaN trong đó * cả hai * vectơ đầu vào có NaN ở cùng vị trí. Chúng ta có thể đặt các NaN trở lại với việc bổ sung một dòng thứ ba vào giải pháp này: 'z [np.isnan (x) & np.isnan (y)] = np.NaN' –