python - tutorial - ¿Detecta si una matriz NumPy contiene al menos un valor no numérico?
numpy tutorial español pdf (4)
Con numpy 1.3 o svn puedes hacer esto
In [1]: a = arange(10000.).reshape(100,100)
In [3]: isnan(a.max())
Out[3]: False
In [4]: a[50,50] = nan
In [5]: isnan(a.max())
Out[5]: True
In [6]: timeit isnan(a.max())
10000 loops, best of 3: 66.3 µs per loop
El tratamiento de nans en las comparaciones no fue consistente en las versiones anteriores.
Necesito escribir una función que detectará si la entrada contiene al menos un valor que no es numérico. Si se encuentra un valor no numérico, generaré un error (porque el cálculo solo debería devolver un valor numérico). El número de dimensiones de la matriz de entrada no se conoce de antemano: la función debe dar el valor correcto independientemente de ndim. Como una complicación adicional, la entrada podría ser un simple float o numpy.float64
o incluso algo raro como una matriz de cero dimensiones.
La forma obvia de resolver esto es escribir una función recursiva que itere sobre cada objeto iterable en la matriz hasta que encuentre un no iterabe. Aplicará la función numpy.isnan()
sobre cada objeto no iterable. Si se encuentra al menos un valor no numérico, la función devolverá False inmediatamente. De lo contrario, si todos los valores en iterable son numéricos, eventualmente devolverá True.
Eso funciona bien, pero es bastante lento y espero que NumPy tenga una forma mucho mejor de hacerlo. ¿Cuál es una alternativa que es más rápida y más numpyish?
Aquí está mi maqueta:
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
Esto debería ser más rápido que iterar y funcionará independientemente de la forma.
numpy.isnan(myarray).any()
Edición: 30 veces más rápido:
import timeit
s = ''import numpy;a = numpy.arange(10000.).reshape((100,100));a[10,10]=numpy.nan''
ms = [
''numpy.isnan(a).any()'',
''any(numpy.isnan(x) for x in a.flatten())'']
for m in ms:
print " %.2f s" % timeit.Timer(m, s).timeit(1000), m
Resultados:
0.11 s numpy.isnan(a).any()
3.75 s any(numpy.isnan(x) for x in a.flatten())
Bonificación: funciona bien para tipos de NumPy que no son de matriz:
>>> a = numpy.float64(42.)
>>> numpy.isnan(a).any()
False
>>> a = numpy.float64(numpy.nan)
>>> numpy.isnan(a).any()
True
Si el infinito es un valor posible, usaría numpy.isfinite
numpy.isfinite(myarray).all()
Si lo anterior se evalúa como True
, entonces myarray
contiene myarray
no, numpy.nan
, numpy.inf
o -numpy.inf
.
numpy.nan
estará bien con los valores de numpy.inf
, por ejemplo:
In [11]: import numpy as np
In [12]: b = np.array([[4, np.inf],[np.nan, -np.inf]])
In [13]: np.isnan(b)
Out[13]:
array([[False, False],
[ True, False]], dtype=bool)
In [14]: np.isfinite(b)
Out[14]:
array([[ True, False],
[False, False]], dtype=bool)
(np.where(np.isnan(A)))[0].shape[0]
será mayor que 0
si A
contiene al menos un elemento de nan
, A
podría ser una matriz nxm
.
Ejemplo:
import numpy as np
A = np.array([1,2,4,np.nan])
if (np.where(np.isnan(A)))[0].shape[0]:
print "A contains nan"
else:
print "A does not contain nan"