2012-08-23 5 views
8

Vorrei aggiungere migliaia di elementi di array 4D saggi e contabilità per nans. Un semplice esempio usando gli array 1D sarebbe:addio veloce numnido

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]) 

Ho scritto un semplice ciclo for intorno a questo, ma ci vuole sempre - non è una soluzione intelligente. Un'altra soluzione potrebbe essere la creazione di un array più grande e l'utilizzo del nasello del collo di bottiglia, ma ciò richiederebbe troppa memoria per il mio laptop. Ho bisogno di una somma corrente su oltre 11000 casi.

Qualcuno ha un modo intelligente e veloce per fare questo?

risposta

10

Ecco una possibilità:

>>> 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.]) 

La vera difficoltà è che ti sembra di voler nan debba essere interpretato nel zero a meno che tutti i valori in una particolare posizione sono nan. Ciò significa che devi guardare sia x che y per determinare quali nans sostituire. Se stai bene con la sostituzione di tutti i valori di nan, allora puoi semplicemente fare np.nan_to_num(x) + np.nan_to_num(y).

+0

Gli array mascherati sono il modo per andare qui se la tua implementazione numpy è abbastanza nuova da supportarla (il mio non lo è - forse è il momento per un aggiornamento) (+1). – mgilson

+0

@mgilson: Heh, probabilmente è il momento! Penso che gli array mascherati siano stati in numpy per alcuni anni. – BrenBarn

+0

Beh, il mio computer ha qualche anno; ^) – mgilson

1

Non so come questo si comporta, ma vale la pena un colpo :)

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) 

questo non si traduca in un NaN all'ultimo posto della matrice però. Essa si traduce in un 0 ...

+2

Numpy fornisce già questo nella funzione 'nan_to_num'. – BrenBarn

+0

@mgilson: una lista di comprensione dopo aver rimosso i nans. Non ho mai pensato alla parte di comprensione delle liste. Ma sospetto che questo presupponga un array 1D. Non riesco a vedere come potrei codificare questo metodo per un array 4D. – Shejo284

+1

@ Shejo284 - In realtà è un'espressione di generatore, ma funziona in modo simile. Non vedo alcun motivo per cui questo non possa essere usato con gli array 4D. In realtà, gli array 4D sono solo array 1D in memoria (a meno che non si possiedano oggetti di visualizzazione, ma dovrebbe comunque funzionare anche con quelli) – mgilson

3

Si potrebbe fare qualcosa di simile:

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]) 

per trovare le posizioni nelle matrici in cui entrambi hanno un NaN in tale indice. Quindi, fare essenzialmente ciò che @mgilson ha suggerito, come nel fare copie e sostituire lo NaN s con 0.0, aggiungere i due array insieme e quindi sostituire gli indici contrassegnati sopra con np.NaN.

+0

@mgilson: Sto cercando di scrivere un'espressione di generatore in quanto consuma meno memoria ma sono un po 'confuso su come funziona quando si gestiscono numeri molto grandi e si legge un file netcdf, slice per slice: per i in casi: array = np.array (netcdfvar [i]) # Quindi sommare queste sezioni tenendo conto di nan non si è sicuri su come dovrebbe essere questo generatore. – Shejo284

+0

@ Shejo284 - Penso che tu abbia postato questo sulla risposta sbagliata ;-). Ad ogni modo, non ho familiarità con la lettura di slice da un file netcdf, ma potreste provare quanto segue: 'sum (nan_to_zero (np.array (netcdfvar [i])) per i in casi)', o come sottolinea BrenBarn : 'sum (np.nan_to_num (netcdfvar [i]) per i in casi)' – mgilson

+0

@mgilson: sì, hai ragione. Sto ancora imparando come usare questo sito. Grazie. Ho provato diverse varianti con un successo variabile. La tua soluzione è un po 'contro intuitiva. Lo proverò. – Shejo284

1

vedo diverse soluzioni più semplici:

  • (a cura) Utilizzo 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) 
    
  • (a cura) Non utilizzando 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

Queste soluzioni non producono l'output desiderato. Vuole che vengano aggiunti i termini non nanometrici, con nan che appare nel risultato solo se i valori * all * in una particolare posizione sono nan. Le tue soluzioni producono nans aggiuntivi in ​​posizioni in cui solo uno dei due vettori di input ha un nan. – BrenBarn

+0

OK, corretto. Grazie per avermi tenuto in punta di piedi –

+0

Nota anche che la tua ultima soluzione è qualcosa che l'OP ha esplicitamente detto che non voleva fare (creare un array più grande contenente entrambi). La seconda soluzione sembra carina, però. – BrenBarn

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

Questo funziona quasi. Il problema è che questa soluzione non produce l'output desiderato. L'output dovrebbe includere NaNs dove * entrambi i vettori di input hanno NaN nelle stesse posizioni. Possiamo rimandare i NaN con l'aggiunta di una terza linea a questa soluzione: 'z [np.isnan (x) & np.isnan (y)] = np.NaN' –