J'ai besoin d'écrire une fonction qui détectera si l'entrée contient au moins une valeur non numérique. Si une valeur non numérique est trouvée, je soulèverai une erreur (car le calcul ne doit renvoyer qu'une valeur numérique). Le nombre de dimensions du tableau d'entrée n'est pas connu à l'avance - la fonction doit donner la valeur correcte indépendamment de ndim. Comme complication supplémentaire, l'entrée peut être un flottant unique numpy.float64
ou même quelque chose de bizarre comme un tableau à zéro dimension.
La manière évidente de résoudre ce problème est d'écrire une fonction récursive qui itère sur chaque objet itérable dans le tableau jusqu'à ce qu'elle trouve un non-itérabe. Il appliquera la numpy.isnan()
fonction sur chaque objet non itérable. Si au moins une valeur non numérique est trouvée, la fonction retournera immédiatement False. Sinon, si toutes les valeurs de l'itérable sont numériques, il renverra finalement True.
Cela fonctionne très bien, mais c'est assez lent et je pense que NumPy a une bien meilleure façon de le faire. Quelle est une alternative plus rapide et plus insensée?
Voici ma maquette:
def contains_nan( myarray ):
"""
@param myarray : An n-dimensional array or a single float
@type myarray : numpy.ndarray, numpy.array, float
@returns: bool
Returns true if myarray is numeric or only contains numeric values.
Returns false if at least one non-numeric value exists
Not-A-Number is given by the numpy.isnan() function.
"""
return True
contains_nan
semble suspecte: "Renvoie false s'il existe au moins une valeur non numérique". Je me serais attenducontains_nan
à revenirTrue
si le tableau contient NaN.array(['None', 'None'], dtype=object)
? Une telle entrée devrait-elle simplement soulever une exception?float('nan') in x
. Ça ne marche pas.Réponses:
Cela devrait être plus rapide que l'itération et fonctionnera quelle que soit la forme.
Edit: 30x plus rapide:
Résultats:
Bonus: cela fonctionne bien pour les types NumPy non-array:
la source
float('nan') in x
ne marche pas? Je l'ai essayé et python revientFalse
oùx = [1,2,3,float('nan')]
.numpy.any
à une genexp renvoie simplement genexp; vous ne faites pas réellement le calcul que vous pensez être. Nenumpy.any
faites jamais appel à un genexp.np.isfinite
lieu denp.isnan
détecter les débordements numériques, l'instabilité, etc.Si l'infini est une valeur possible, j'utiliserais numpy.isfinite
Si la valeur ci-dessus est évaluée à
True
, alorsmyarray
ne contient aucune valeurnumpy.nan
,numpy.inf
ou-numpy.inf
.numpy.nan
sera OK avec lesnumpy.inf
valeurs, par exemple:la source
float('nan') in x
ne marche pas? Je l'ai essayé et python revientFalse
oùx = [1,2,3,float('nan')]
.nan
s ne sont pas considérés comme égaux l'un à l'autre. Essayezfloat('nan') == float('nan')
.Pfft! Microsecondes! Ne résolvez jamais un problème en microsecondes qui peut être résolu en nanosecondes.
Notez que la réponse acceptée:
Une meilleure solution consiste à renvoyer True immédiatement lorsque NAN est trouvé:
et fonctionne pour n-dimensions:
Comparez cela à la solution native numpy:
La méthode de sortie anticipée est une accélération de 3 ordres ou de magnitude (dans certains cas). Pas trop minable pour une simple annotation.
la source
Avec numpy 1.3 ou svn, vous pouvez le faire
Le traitement des nans dans les comparaisons n'était pas cohérent dans les versions antérieures.
la source
float('nan') in x
ne marche pas? Je l'ai essayé et python revientFalse
oùx = [1,2,3,float('nan')]
.float("nan")==float("nan")
donnerFalse
(bien que cela soit possible, il devrait probablement retourner NAN ou None). De même, la bizarrerie avec NAN et boolen NULL est vraie dans de nombreux langages, y compris SQL (où NULL = NULL n'est jamais vrai).(np.where(np.isnan(A)))[0].shape[0]
sera plus grand que0
siA
contient au moins un élément denan
,A
pourrait être unen x m
matrice.Exemple:
la source