139 votes

Vérification rapide des NaN dans NumPy

Je cherche le moyen le plus rapide de vérifier l'occurrence de NaN ( np.nan ) dans un tableau NumPy X . np.isnan(X) est hors de question, puisqu'il construit un tableau booléen de forme X.shape ce qui est potentiellement gigantesque.

J'ai essayé np.nan in X mais cela ne semble pas fonctionner car np.nan != np.nan . Existe-t-il un moyen rapide et peu gourmand en mémoire d'effectuer cette opération ?

(Pour ceux qui demanderaient "à quel point c'est gigantesque" : Je ne peux pas le dire. Il s'agit d'une validation d'entrée pour le code de la bibliothèque).

0 votes

La validation de l'entrée de l'utilisateur ne fonctionne-t-elle pas dans ce scénario ? Comme dans le cas d'une vérification de NaN avant l'insertion.

0 votes

@Woot4Moo : non, la bibliothèque prend les tableaux NumPy ou scipy.sparse en tant que données d'entrée.

2 votes

Si vous faites cela souvent, j'ai entendu de bonnes choses à propos de Bottleneck ( pypi.python.org/pypi/Bottleneck )

5voto

woso Points 81
  1. utiliser .any()

    if numpy.isnan(myarray).any()

  2. numpy.isfinite est peut-être meilleur que isnan pour la vérification

    if not np.isfinite(prop).all()

1voto

Garrett Linux Points 136

La question de savoir comment trouver la première occurrence de NaN est liée à cette question. À ma connaissance, il s'agit de la méthode la plus rapide pour répondre à cette question :

index = next((i for (i,n) in enumerate(iterable) if n!=n), None)

0voto

erwanp Points 986

En complément des réponses de @nico-schlömer et @mseifert, j'ai calculé la performance d'un numba-test has_nan avec des arrêts précoces, par rapport à certaines fonctions qui analysent le tableau complet.

Sur ma machine, pour un tableau sans nans, le seuil de rentabilité est atteint pour ~10^4 éléments.

has_nan_vs_full_parse_methods

import perfplot
import numpy as np
import numba
import math

def min(a):
    return np.isnan(np.min(a))

def dot(a):
    return np.isnan(np.dot(a, a))

def einsum(a):
    return np.isnan(np.einsum("i->", a))

@numba.njit
def has_nan(a):
    for i in range(a.size - 1):
        if math.isnan(a[i]):
            return True
    return False

def array_with_missing_values(n, p):
    """ Return array of size n,  p : nans ( % of array length )
    Ex : n=1e6, p=1 : 1e4 nan assigned at random positions """
    a = np.random.rand(n)
    p = np.random.randint(0, len(a), int(p*len(a)/100))
    a[p] = np.nan
    return a

#%%
perfplot.show(
    setup=lambda n: array_with_missing_values(n, 0),
    kernels=[min, dot, has_nan],
    n_range=[2 ** k for k in range(20)],
    logx=True,
    logy=True,
    xlabel="len(a)",
)

Que se passe-t-il si le tableau a des nans ? J'ai étudié l'impact de la couverture nanométrique du réseau.

Pour les tableaux de longueur 1 000 000, has_nan devient une meilleure option s'il y a ~10^-3 % de nans (donc ~10 nans) dans le tableau.

impact of nan-coverage of array

#%%
N = 1000000  # 100000
perfplot.show(
    setup=lambda p: array_with_missing_values(N, p),
    kernels=[min, dot, has_nan],
    n_range=np.array([2 ** k for k in range(20)]) / 2**20 * 0.01, 
    logy=True,
    xlabel=f"% of nan in array (N = {N})",
)

Si, dans votre application, la plupart des tableaux ont nan et que vous en recherchez d'autres qui n'en ont pas, alors has_nan est la meilleure approche. Autre ; dot semble être la meilleure option.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X