Inicialización de matriz NumPy (rellenar con valores idénticos)

237

Necesito crear una matriz de longitud NumPy n, cada elemento de los cuales es v.

¿Hay algo mejor que:

a = empty(n)
for i in range(n):
    a[i] = v

zerosy onesfuncionaría para v = 0, 1. Podría usar v * ones(n), pero no funcionará cuando lo vesté None, y también sería mucho más lento.

max
fuente
1
En mi computadora, para el caso 0, usar a = np.zeros(n)en el bucle es más rápido que a.fill(0). Esto es contrario a lo que esperaba, ya que pensé a=np.zeros(n)que necesitaría asignar e inicializar nueva memoria. Si alguien puede explicar esto, lo agradecería.
user3731622
No puede colocar None en una matriz numpy, ya que las celdas se crean con un tipo de datos específico, mientras que None tiene su propio tipo y, de hecho, es un puntero.
Camion
@Camion Sí, ahora lo sé :) Por supuesto, v * ones(n)todavía es horrible, ya que utiliza la costosa multiplicación. Sin embargo, reemplace *con +, y v + zeros(n)resulta ser sorprendentemente bueno en algunos casos ( stackoverflow.com/questions/5891410/… ).
max
max, en lugar de crear una matriz con ceros antes de agregar v, es aún más rápido crearlo vacío var = np.empty(n)y luego llenarlo con 'var [:] = v'. (por cierto, np.full()es tan rápido como esto)
Camion

Respuestas:

308

Se introdujo NumPy 1.8 np.full(), que es un método más directo que el empty()seguido fill()para crear una matriz llena de un cierto valor:

>>> np.full((3, 5), 7)
array([[ 7.,  7.,  7.,  7.,  7.],
       [ 7.,  7.,  7.,  7.,  7.],
       [ 7.,  7.,  7.,  7.,  7.]])

>>> np.full((3, 5), 7, dtype=int)
array([[7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7]])

Esta es posiblemente la forma de crear una matriz llena de ciertos valores, porque describe explícitamente lo que se está logrando (y en principio puede ser muy eficiente ya que realiza una tarea muy específica).

Eric O Lebigot
fuente
1
Este método full () funciona bien para mí, pero no puedo encontrar un poco de documentación. ¿Alguien puede señalarme el lugar correcto?
James Adams
1
Al menos puedes hacerlo help(numpy.full)en un shell de Python. También me sorprende que no esté en la documentación web.
Eric O Lebigot
En mi sistema (Python 2.7, Numpy 1.8), np.full () es en realidad un poco más lento que np.empty () seguido de np.fill ().
John Zwinck
1
Para 10,000 elementos, observo lo mismo (excepto que np.fill()no existe y debería existir arr.fill()), con una diferencia de aproximadamente 10%. Si la diferencia fuera mayor, plantearía un problema en el rastreador de errores NumPy. :) Prefiero un código más explícito y más claro, por una diferencia tan pequeña en el tiempo de ejecución, así que voy con np.full()todo el tiempo.
Eric O Lebigot
En mi máquina np.full () tiene la misma velocidad que np.array.fill ()
Fnord
92

Actualizado para Numpy 1.7.0: (Hat-tip a @Rolf Bartstra.)

a=np.empty(n); a.fill(5) Es el más rápido.

En orden de velocidad descendente:

%timeit a=np.empty(1e4); a.fill(5)
100000 loops, best of 3: 5.85 us per loop

%timeit a=np.empty(1e4); a[:]=5 
100000 loops, best of 3: 7.15 us per loop

%timeit a=np.ones(1e4)*5
10000 loops, best of 3: 22.9 us per loop

%timeit a=np.repeat(5,(1e4))
10000 loops, best of 3: 81.7 us per loop

%timeit a=np.tile(5,[1e4])
10000 loops, best of 3: 82.9 us per loop
Yariv
fuente
13
Agregar un momento para el más reciente y directo np.full()sería útil. En mi máquina, con NumPy 1.8.1, es aproximadamente un 15% más lento que la fill()versión menos directa (lo cual es inesperado, ya que full()tiene el potencial de ir un poco más rápido).
Eric O Lebigot
@DavidSanders: No estoy seguro de seguirte: fill()es la solución más rápida. La solución de multiplicación es mucho más lenta.
Eric O Lebigot
2
Nota: si la velocidad es realmente una preocupación, usar un tamaño en 10000lugar de 1e4hacer una diferencia notable, por alguna razón ( full()es casi un 50% más lento, con 1e4).
Eric O Lebigot
Simplemente agregando mis resultados full(), se ejecuta considerablemente más lento cuando el tipo de datos no es explícitamente flotante. De lo contrario, es comparable (pero un poco más lento) con los mejores métodos aquí.
user2699
@ user2699 No estoy observando esto, con 100.000 elementos: full(100000, 5), full(100000, 5, dtype=float), full(100000, 5, dtype=int)y a =np.empty(100000); a.fill(5)todos toman casi al mismo tiempo en mi máquina (sin almacenamiento en caché: %timeit -r1 -n1 …) (NumPy 1.11.2).
Eric O Lebigot
65

Creo que filles la forma más rápida de hacer esto.

a = np.empty(10)
a.fill(7)

También debe evitar siempre iterar como lo hace en su ejemplo. Un simple a[:] = vlogrará lo que hace su iteración usando una transmisión numpy .

Pablo
fuente
1
Gracias. Al mirar fill, vi que se repeatadapta aún mejor a mis necesidades.
max
¿Le importaría actualizar su respuesta para decir que su recomendación a[:]=ves realmente más rápida en general que la fill?
máximo
@max ¿Es más rápido? La difusión es una forma más general de llenar una matriz y supongo que es más lenta o igual al caso de uso muy limitado de fill.
Paul
16

Aparentemente, no solo las velocidades absolutas sino también el orden de velocidad (según lo informado por el usuario 1579844) dependen de la máquina; esto es lo que encontré:

a=np.empty(1e4); a.fill(5) es el más rápido

En orden de velocidad descendente:

timeit a=np.empty(1e4); a.fill(5) 
# 100000 loops, best of 3: 10.2 us per loop
timeit a=np.empty(1e4); a[:]=5
# 100000 loops, best of 3: 16.9 us per loop
timeit a=np.ones(1e4)*5
# 100000 loops, best of 3: 32.2 us per loop
timeit a=np.tile(5,[1e4])
# 10000 loops, best of 3: 90.9 us per loop
timeit a=np.repeat(5,(1e4))
# 10000 loops, best of 3: 98.3 us per loop
timeit a=np.array([5]*int(1e4))
# 1000 loops, best of 3: 1.69 ms per loop (slowest BY FAR!)

Por lo tanto, intente averiguarlo y use lo que es más rápido en su plataforma.

Rolf Bartstra
fuente
14

yo tenía

numpy.array(n * [value])

en mente, pero aparentemente eso es más lento que todas las demás sugerencias para lo suficientemente grande n.

Aquí hay una comparación completa con perfplot (un proyecto mío favorito).

ingrese la descripción de la imagen aquí

Las dos emptyalternativas siguen siendo las más rápidas (con NumPy 1.12.1). fullse pone al día con grandes matrices.


Código para generar la trama:

import numpy as np
import perfplot


def empty_fill(n):
    a = np.empty(n)
    a.fill(3.14)
    return a


def empty_colon(n):
    a = np.empty(n)
    a[:] = 3.14
    return a


def ones_times(n):
    return 3.14 * np.ones(n)


def repeat(n):
    return np.repeat(3.14, (n))


def tile(n):
    return np.repeat(3.14, [n])


def full(n):
    return np.full((n), 3.14)


def list_to_array(n):
    return np.array(n * [3.14])


perfplot.show(
    setup=lambda n: n,
    kernels=[empty_fill, empty_colon, ones_times, repeat, tile, full, list_to_array],
    n_range=[2 ** k for k in range(27)],
    xlabel="len(a)",
    logx=True,
    logy=True,
)
Nico Schlömer
fuente
7

Puede usar numpy.tile, por ejemplo:

v = 7
rows = 3
cols = 5
a = numpy.tile(v, (rows,cols))
a
Out[1]: 
array([[7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7],
       [7, 7, 7, 7, 7]])

Aunque tileestá destinado a 'en mosaico' una matriz (en lugar de un escalar, como en este caso), hará el trabajo, creando matrices precargadas de cualquier tamaño y dimensión.

Rolf Bartstra
fuente
5

sin numpy

>>>[2]*3
[2, 2, 2]
tnusraddinov
fuente
Sugerir [v] * nsería más directamente relevante a la pregunta de OP.
encendido
Esta respuesta ya mencionó este enfoque.
CommonSense