Crea matrice intorpidita riempita con NaNs


195

Ho il codice seguente:

r = numpy.zeros(shape = (width, height, 9))

Crea una width x height x 9matrice piena di zeri. Invece, vorrei sapere se esiste una funzione o un modo per inizializzarli invece che NaNin modo semplice.


2
Un avvertimento è che NumPy non ha un valore NA intero (a differenza di R). Vedi la lista dei panda dei gotcha . Quindi np.nanva storto quando convertito in int.
smci,

smci ha ragione. Per NumPy non esiste tale valore NaN. Quindi dipende dal tipo e da NumPy quale valore sarà presente per NaN. Se non sei a conoscenza di questo, causerà problemi
MasterControlProgram

Risposte:


271

Raramente sono necessari loop per operazioni vettoriali in numpy. È possibile creare un array non inizializzato e assegnarlo a tutte le voci contemporaneamente:

>>> a = numpy.empty((3,3,))
>>> a[:] = numpy.nan
>>> a
array([[ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN]])

Ho cronometrato le alternative a[:] = numpy.nanqui e a.fill(numpy.nan)come pubblicato da Blaenk:

$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)"
10000 loops, best of 3: 54.3 usec per loop
$ python -mtimeit "import numpy as np; a = np.empty((100,100));" "a[:] = np.nan" 
10000 loops, best of 3: 88.8 usec per loop

I tempi mostrano una preferenza ndarray.fill(..)come alternativa più veloce. OTOH, mi piace l'implementazione della comodità di numpy in cui è possibile assegnare valori a intere porzioni in quel momento, l'intenzione del codice è molto chiara.

Si noti che ndarray.fillesegue l'operazione sul posto, quindi numpy.empty((3,3,)).fill(numpy.nan)tornerà invece None.


8
Sono d'accordo che l'intenzione del tuo codice sia più chiara. Ma grazie per gli orari imparziali (o meglio, per il fatto che li hai ancora pubblicati), lo apprezzo :)
Jorge Israel Peña,

2
Ho come questo: a = numpy.empty((3, 3,)) * numpy.nan. Ha una tempistica più veloce di fillma più lenta del metodo di assegnazione, ma è un oneliner !!
heltonbiker,

2
Si prega di guardare questa risposta: stackoverflow.com/questions/10871220/…
Ivan

3
Preferisco il .fill()metodo, ma la differenza di velocità si riduce praticamente a nulla man mano che gli array diventano più grandi.
naught101

4
... perché np.empty([2, 5])crea un array, quindi fill()modifica tale array sul posto, ma non restituisce una copia o un riferimento. Se si desidera chiamare np.empty(2, 5)con un nome ("assegnare è a una variabile"), è necessario farlo prima di eseguire operazioni sul posto su di esso. La stessa cosa succede se lo fai [1, 2, 3].insert(1, 4). L'elenco viene creato e viene inserito un 4, ma è impossibile ottenere un riferimento all'elenco (e quindi si può presumere che sia stato raccolto in modo inutile). Su dati immutabili come le stringhe, viene restituita una copia, perché non è possibile operare sul posto. I panda possono fare entrambe le cose.
flutefreak7,

164

Un'altra opzione è usare numpy.full, un'opzione disponibile in NumPy 1.8+

a = np.full([height, width, 9], np.nan)

Questo è abbastanza flessibile e puoi riempirlo con qualsiasi altro numero che desideri.


19
Considererei questa come la risposta più corretta dal momento che è decisamente ciò che fullè destinato. np.empy((x,y))*np.nanè un buon secondo classificato (e compatibilità per le vecchie versioni di numpy).
travc,

questo è più lentofill python -mtimeit "import numpy as np; a = np.empty((100,100));" "a.fill(np.nan)" 100000 loops, best of 3: 13.3 usec per loop python -mtimeit "import numpy as np; a = np.full((100,100), np.nan);" 100000 loops, best of 3: 18.5 usec per loop
Farnabaz,

5
@Farnabaz Se inserisci il codice equivalente all'interno del circuito di temporizzazione, sono quasi uguali. I due metodi sono sostanzialmente uguali, hai appena ottenuto "np.empty" fuori dal timer nel primo. python -mtimeit "import numpy as np; a = np.empty((1000,1000)); a.fill(np.nan)" 1000 loops, best of 3: 381 usec per loop $ python -mtimeit "import numpy as np; a = np.full((1000,1000), np.nan);" 1000 loops, best of 3: 383 usec per loop
Scott Staniewicz,

50

Ho confrontato le alternative suggerite per la velocità e ho scoperto che, per vettori / matrici abbastanza grandi da riempire, tutte le alternative tranne val * onese array(n * [val])sono ugualmente veloci.

inserisci qui la descrizione dell'immagine


Codice per riprodurre la trama:

import numpy
import perfplot

val = 42.0


def fill(n):
    a = numpy.empty(n)
    a.fill(val)
    return a


def colon(n):
    a = numpy.empty(n)
    a[:] = val
    return a


def full(n):
    return numpy.full(n, val)


def ones_times(n):
    return val * numpy.ones(n)


def list(n):
    return numpy.array(n * [val])


perfplot.show(
    setup=lambda n: n,
    kernels=[fill, colon, full, ones_times, list],
    n_range=[2 ** k for k in range(20)],
    logx=True,
    logy=True,
    xlabel="len(a)",
)

Strano che numpy.full(n, val)sia più lento di a = numpy.empty(n) .. a.fill(val)da quando fa la stessa cosa internamente
endolith

26

Hai familiarità con numpy.nan?

Puoi creare il tuo metodo come:

def nans(shape, dtype=float):
    a = numpy.empty(shape, dtype)
    a.fill(numpy.nan)
    return a

Poi

nans([3,4])

sarebbe uscita

array([[ NaN,  NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN,  NaN]])

Ho trovato questo codice in un thread della mailing list .


1
Sembra eccessivo.
Fisico pazzo,

@MadPhysicist Dipende interamente dalla tua situazione. Se devi inizializzare solo un singolo array NaN, sì, probabilmente una funzione personalizzata è eccessiva. Tuttavia, se devi inizializzare un array NaN in dozzine di posizioni nel tuo codice, avere questa funzione diventa abbastanza conveniente.
Xukrao,

1
@Xukaro. Non proprio, dato che esiste già una versione più flessibile ed efficiente di tale funzione ed è menzionata in più altre risposte.
Fisico pazzo,

10

Puoi sempre usare la moltiplicazione se non ricordi immediatamente i metodi .emptyo .full:

>>> np.nan * np.ones(shape=(3,2))
array([[ nan,  nan],
       [ nan,  nan],
       [ nan,  nan]])

Ovviamente funziona anche con qualsiasi altro valore numerico:

>>> 42 * np.ones(shape=(3,2))
array([[ 42,  42],
       [ 42,  42],
       [ 42, 42]])

Ma la risposta accettata da @u0b34a0f6ae è 3 volte più veloce (cicli CPU, non cicli cerebrali per ricordare la sintassi intorpidita;):

$ python -mtimeit "import numpy as np; X = np.empty((100,100));" "X[:] = np.nan;"
100000 loops, best of 3: 8.9 usec per loop
(predict)laneh@predict:~/src/predict/predict/webapp$ master
$ python -mtimeit "import numpy as np; X = np.ones((100,100));" "X *= np.nan;"
10000 loops, best of 3: 24.9 usec per loop

6

Un'altra alternativa è quella numpy.broadcast_to(val,n)che ritorna in tempo costante indipendentemente dalle dimensioni ed è anche la memoria più efficiente (restituisce una vista dell'elemento ripetuto). L'avvertenza è che il valore restituito è di sola lettura.

Di seguito è riportato un confronto delle prestazioni di tutti gli altri metodi che sono stati proposti utilizzando lo stesso benchmark della risposta di Nico Schlömer .

inserisci qui la descrizione dell'immagine


5

Come detto, numpy.empty () è la strada da percorrere. Tuttavia, per gli oggetti, fill () potrebbe non fare esattamente quello che pensi che faccia:

In[36]: a = numpy.empty(5,dtype=object)
In[37]: a.fill([])
In[38]: a
Out[38]: array([[], [], [], [], []], dtype=object)
In[39]: a[0].append(4)
In[40]: a
Out[40]: array([[4], [4], [4], [4], [4]], dtype=object)

Un modo per aggirare può essere ad esempio:

In[41]: a = numpy.empty(5,dtype=object)
In[42]: a[:]= [ [] for x in range(5)]
In[43]: a[0].append(4)
In[44]: a
Out[44]: array([[4], [], [], [], []], dtype=object)

Oltre a non avere praticamente nulla a che fare con la domanda originale, pulito.
Fisico pazzo,

1
Bene, si tratta di "Inizializzare la matrice numpy su qualcosa di diverso da zero o uno", nel caso "qualcosa di diverso" è un oggetto :) (Più praticamente, google mi ha portato qui per l'inizializzazione con un elenco vuoto)
ntg

3

Ancora un'altra possibilità non ancora menzionata qui è di usare il riquadro NumPy:

a = numpy.tile(numpy.nan, (3, 3))

Dà anche

array([[ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN],
       [ NaN,  NaN,  NaN]])

Non conosco il confronto di velocità.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.