Contando il numero di elementi non NaN in un numpy ndarray in Python


90

Devo calcolare il numero di elementi non NaN in una matrice numpy ndarray. Come si può fare questo in modo efficiente in Python? Ecco il mio semplice codice per raggiungere questo obiettivo:

import numpy as np

def numberOfNonNans(data):
    count = 0
    for i in data:
        if not np.isnan(i):
            count += 1
    return count 

C'è una funzione incorporata per questo in numpy? L'efficienza è importante perché sto facendo analisi dei Big Data.

Grazie per qualsiasi aiuto!


2
Questa domanda sembra essere fuori tema perché appartiene a codereview.stackexchange.com
jonrsharpe

1
Intendi efficiente in termini di memoria?
Ashwini Chaudhary

+1 Stavo pensando al tempo della CPU, ma sì, perché non anche alla memoria. Più veloce ed economico è, meglio è =)
jjepsuomi

3
@jjepsuomi Una versione efficiente sum(not np.isnan(x) for x in a)in termini di memoria sarà , ma in termini di velocità è lenta rispetto alla versione numpy di @ M4rtini.
Ashwini Chaudhary

@AshwiniChaudhary Grazie mille! Devo vedere quale è più importante nella mia domanda =)
jjepsuomi

Risposte:


164
np.count_nonzero(~np.isnan(data))

~inverte la matrice booleana da cui proviene np.isnan.

np.count_nonzeroconta i valori che non sono 0 \ false. .sumdovrebbe dare lo stesso risultato. Ma forse più chiaramente da usarecount_nonzero

Velocità di prova:

In [23]: data = np.random.random((10000,10000))

In [24]: data[[np.random.random_integers(0,10000, 100)],:][:, [np.random.random_integers(0,99, 100)]] = np.nan

In [25]: %timeit data.size - np.count_nonzero(np.isnan(data))
1 loops, best of 3: 309 ms per loop

In [26]: %timeit np.count_nonzero(~np.isnan(data))
1 loops, best of 3: 345 ms per loop

In [27]: %timeit data.size - np.isnan(data).sum()
1 loops, best of 3: 339 ms per loop

data.size - np.count_nonzero(np.isnan(data))sembra essere a malapena il più veloce qui. altri dati potrebbero fornire risultati di velocità relativa diversi.


+1 @ M4rtini grazie ancora! Sei grande! ; DI accetterà la tua risposta appena posso :)
jjepsuomi

3
Forse anche numpy.isnan(array).sum()? Non sono molto esperto con numpy però.
msvalkon

2
@msvalkon, conterà il numero di NaN, mentre OP vuole il numero di elementi non NaN.
falsetru


5
Un'estensione della risposta @msvalkon: data.size - np.isnan(data).sum()sarà leggermente più efficiente.
Daniel

11

Alternativa veloce da scrivere

Anche se non è la scelta più veloce, se le prestazioni non sono un problema puoi usare:

sum(~np.isnan(data)).

Prestazione:

In [7]: %timeit data.size - np.count_nonzero(np.isnan(data))
10 loops, best of 3: 67.5 ms per loop

In [8]: %timeit sum(~np.isnan(data))
10 loops, best of 3: 154 ms per loop

In [9]: %timeit np.sum(~np.isnan(data))
10 loops, best of 3: 140 ms per loop

Questa risposta fornisce la somma che non è la stessa del conteggio del numero di elementi ... Dovresti leninvece usare .
BenT

1
@BenT la somma degli elementi di un array bool che soddisfano una determinata condizione è la stessa che fornisce la durata di un array di sottoinsiemi con gli elementi che soddisfano una determinata condizione. Puoi per favore chiarire dove questo è sbagliato?
GM

2
Errore mio, ho dimenticato che un booleano è tornato.
BenT

3

Un'alternativa, ma un po 'più lenta, è quella di farlo tramite indicizzazione.

np.isnan(data)[np.isnan(data) == False].size

In [30]: %timeit np.isnan(data)[np.isnan(data) == False].size
1 loops, best of 3: 498 ms per loop 

Il doppio uso di np.isnan(data)e l' ==operatore potrebbe essere un po 'eccessivo e quindi ho postato la risposta solo per completezza.


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.