Crear matriz numpy llena de NaN

195

Tengo el siguiente código:

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

Crea una width x height x 9matriz llena de ceros. En cambio, me gustaría saber si hay una función o forma de inicializarlos en lugar de hacerlo NaNde una manera fácil.

elysium devorado
fuente
2
Una advertencia es que NumPy no tiene un valor de NA entero (a diferencia de R). Ver la lista de pandas de las trampas . Por lo tanto, np.nansale mal cuando se convierte a int.
smci
smci tiene razón. Para NumPy no existe dicho valor de NaN. Por lo tanto, depende del tipo y de NumPy qué valor estará allí para NaN. Si no está al tanto de esto, causará problemas
MasterControlProgram

Respuestas:

271

Raramente necesita bucles para operaciones vectoriales en numpy. Puede crear una matriz no inicializada y asignarla a todas las entradas a la vez:

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

He cronometrado las alternativas a[:] = numpy.nanaquí y a.fill(numpy.nan)según lo publicado por 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

Los tiempos muestran una preferencia ndarray.fill(..)como la alternativa más rápida. OTOH, me gusta la implementación de conveniencia de numpy donde puede asignar valores a segmentos enteros en ese momento, la intención del código es muy clara.

Tenga en cuenta que ndarray.fillrealiza su operación en el lugar, por numpy.empty((3,3,)).fill(numpy.nan)lo que en su lugar regresará None.

u0b34a0f6ae
fuente
8
Estoy de acuerdo en que la intención de su código es más clara. Pero gracias por los horarios imparciales (o más bien, el hecho de que todavía los publicaste), lo aprecio :)
Jorge Israel Peña
2
Yo como éste: a = numpy.empty((3, 3,)) * numpy.nan. ¡Se cronometró más rápido fillpero más lento que el método de asignación, pero es una línea!
heltonbiker
2
Mire esta respuesta: stackoverflow.com/questions/10871220/…
Ivan
3
Prefiero el .fill()método, pero la diferencia de velocidades se reduce a prácticamente nada a medida que las matrices se hacen más grandes.
naught101
44
... porque np.empty([2, 5])crea una matriz, luego fill()modifica esa matriz en el lugar, pero no devuelve una copia o una referencia. Si desea llamar np.empty(2, 5)por un nombre ("asignar es a una variable"), debe hacerlo antes de realizar operaciones in situ en él. Lo mismo pasa si lo haces [1, 2, 3].insert(1, 4). Se crea la lista y se inserta un 4, pero es imposible obtener una referencia a la lista (y, por lo tanto, se puede suponer que se ha recolectado basura). En datos inmutables como cadenas, se devuelve una copia, porque no puede operar en el lugar. Los pandas pueden hacer ambas cosas.
flutefreak7
164

Otra opción es usar numpy.full, una opción disponible en NumPy 1.8+

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

Esto es bastante flexible y puede llenarlo con cualquier otro número que desee.

Pietro Biroli
fuente
19
Consideraría esto como la respuesta más correcta, ya que es exactamente para lo que fullestá destinado. np.empy((x,y))*np.nanes un buen finalista (y compatibilidad para versiones antiguas de numpy).
travc
esto es más lento quefill 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
55
@Farnabaz Si coloca el código equivalente dentro del ciclo de sincronización, son casi iguales. Los dos métodos son básicamente iguales, acaba de obtener el "np.empty" fuera del temporizador en el primero. 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
48

Comparé las alternativas sugeridas para la velocidad y descubrí que, para vectores / matrices lo suficientemente grandes como para llenar, todas las alternativas excepto val * onesy array(n * [val])son igualmente rápidas.

ingrese la descripción de la imagen aquí


Código para reproducir 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)",
)
Nico Schlömer
fuente
Es extraño que numpy.full(n, val)sea ​​más lento que a = numpy.empty(n) .. a.fill(val)porque hace lo mismo internamente
endolito el
26

¿Estás familiarizado con numpy.nan?

Puede crear su propio método, como:

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

Luego

nans([3,4])

saldría

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

Encontré este código en un hilo de la lista de correo .

Jorge Israel Peña
fuente
1
Parece una exageración.
Físico loco
@MadPhysicist Eso depende completamente de tu situación. Si tiene que inicializar solo una única matriz NaN, entonces sí, una función personalizada probablemente sea exagerada. Sin embargo, si tiene que inicializar una matriz NaN en docenas de lugares en su código, entonces tener esta función se vuelve bastante conveniente.
Xukrao
1
@Xukaro. En realidad no, dado que ya existe una versión más flexible y eficiente de dicha función y se menciona en muchas otras respuestas.
Físico loco
10

Siempre puede usar la multiplicación si no recuerda inmediatamente los métodos .emptyo .full:

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

Por supuesto, también funciona con cualquier otro valor numérico:

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

Pero el @ u0b34a0f6ae's respuesta aceptada de es 3 veces más rápida (ciclos de CPU, no ciclos cerebrales para recordar sintaxis numpy;):

$ 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
placas
fuente
6

Otra alternativa es numpy.broadcast_to(val,n) que regresa en tiempo constante sin importar el tamaño y también es la memoria más eficiente (devuelve una vista del elemento repetido). La advertencia es que el valor devuelto es de solo lectura.

A continuación se muestra una comparación de las actuaciones de todos los otros métodos que se han propuesto utilizando el mismo punto de referencia que en la respuesta de Nico Schlömer .

ingrese la descripción de la imagen aquí

Giancarlo Sportelli
fuente
5

Como se dijo, numpy.empty () es el camino a seguir. Sin embargo, para los objetos, fill () podría no hacer exactamente lo que cree que hace:

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)

Una forma de evitarlo puede ser, por ejemplo:

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)
ntg
fuente
Aparte de no tener prácticamente nada que ver con la pregunta original, ordenada.
Mad Physicist
1
Bueno, se trata de "Inicializar matriz numpy en algo diferente a cero o uno", en el caso de "algo más" es un objeto :) (Más prácticamente, google me llevó aquí para inicializar con una lista vacía)
ntg
3

Otra posibilidad aún no mencionada aquí es usar el mosaico NumPy:

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

También da

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

No sé sobre la comparación de velocidad.

JHBonarius
fuente