Inizializzazione dell'array NumPy (riempire con valori identici)


237

Ho bisogno di creare un array NumPy di ​​lunghezza n, ciascuno dei quali è v.

C'è qualcosa di meglio di:

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

Lo so zerose onesfunzionerebbe per v = 0, 1. Potrei usare v * ones(n), ma non funzionerà quando vè None, e sarebbe anche molto più lento.


1
Sul mio computer, per il caso 0, l'utilizzo a = np.zeros(n)nel ciclo è più veloce di a.fill(0). Questo è in contrasto con quello che mi aspettavo da quando pensavo che a=np.zeros(n)avrei dovuto allocare e inizializzare la nuova memoria. Se qualcuno può spiegarlo, lo apprezzerei.
user3731622

Non è possibile inserire Nonein in un array numpy, poiché le celle vengono create con un tipo di dati specifico mentre None ha il proprio tipo ed è in realtà un puntatore.
Camion

@Camion Sì, lo so ora :) Naturalmente v * ones(n)è ancora orribile, in quanto utilizza la costosa moltiplicazione. Sostituisci *con +però e v + zeros(n)in alcuni casi risulta sorprendentemente buono ( stackoverflow.com/questions/5891410/… ).
max

max, invece di creare un array con zeri prima di aggiungere v, è ancora più veloce crearlo vuoto con var = np.empty(n)e quindi riempirlo con 'var [:] = v'. (a proposito, np.full()è veloce come questo)
Camion

Risposte:


308

Introduzione di NumPy 1.8 np.full(), che è un metodo più diretto di quello empty()seguito fill()per creare un array riempito con un certo valore:

>>> 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]])

Questo è probabilmente il modo di creare un array pieno di determinati valori, perché descrive esplicitamente ciò che viene raggiunto (e in linea di principio può essere molto efficiente poiché svolge un compito molto specifico).


1
Questo metodo full () funziona bene per me, ma non riesco a trovare un po 'di documentazione per questo. Qualcuno può indicarmi il posto giusto?
James Adams,

1
Puoi almeno farlo help(numpy.full)in una shell Python. Sono anche sorpreso che non sia nella documentazione web.
Eric O Lebigot,

Sul mio sistema (Python 2.7, Numpy 1.8), np.full () è in realtà leggermente più lento di np.empty () seguito da np.fill ().
John Zwinck,

1
Per 10.000 elementi, osservo la stessa cosa (tranne che np.fill()non esiste e dovrebbe essere arr.fill()), con una differenza di circa il 10%. Se la differenza fosse maggiore, solleverei un problema nel tracker dei bug di NumPy. :) Preferisco un codice più esplicito e più chiaro, per una differenza così piccola nel tempo di esecuzione, quindi vado sempre con me np.full().
Eric O Lebigot,

Sulla mia macchina np.full () ha la stessa velocità di np.array.fill ()
Fnord

92

Aggiornato per Numpy 1.7.0: (Hat-tip a @Rolf Bartstra.)

a=np.empty(n); a.fill(5) è il più veloce.

In ordine decrescente di velocità:

%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

13
np.full()Sarebbe utile aggiungere una tempistica per i più recenti e diretti . Sulla mia macchina, con NumPy 1.8.1, è circa il 15% più lento rispetto alla fill()versione meno diretta (il che è inaspettato, poiché full()ha il potenziale di andare leggermente più veloce).
Eric O Lebigot,

@DavidSanders: non sono sicuro di seguirti: fill()è la soluzione più veloce. La soluzione di moltiplicazione è molto più lenta.
Eric O Lebigot,

2
Nota: se la velocità è davvero un problema, usare una dimensione 10000invece di 1e4fare una differenza evidente, per qualche motivo ( full()è quasi il 50% più lento, con 1e4).
Eric O Lebigot,

Aggiungendo semplicemente i miei risultati full(), è molto più lento quando il tipo di dati non è esplicitamente un float. Altrimenti, è comparabile (ma leggermente più lento) con i migliori metodi qui.
user2699

@ user2699 Io non sto osservando questo, con 100.000 elementi: full(100000, 5), full(100000, 5, dtype=float), full(100000, 5, dtype=int)e a =np.empty(100000); a.fill(5)tutti prendono circa lo stesso tempo sulla mia macchina (senza caching: %timeit -r1 -n1 …) (NumPy 1.11.2).
Eric O Lebigot,

65

Credo che fillsia il modo più veloce per farlo.

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

Dovresti anche evitare sempre di iterare come stai facendo nel tuo esempio. Un semplice a[:] = vcompirà ciò che fa la tua iterazione usando la trasmissione numpy .


1
Grazie. Guardando fill, ho visto che repeatsi adattava ancora meglio alle mie esigenze.
max

Ti dispiace aggiornare la tua risposta per dire che la tua raccomandazione a[:]=vè in realtà più veloce nel complesso fill?
massimo

@max È più veloce? La trasmissione è un modo più generale per riempire un array e immagino sia più lento o uguale al caso d'uso molto ristretto di fill.
Paul,

16

Apparentemente, non solo le velocità assolute ma anche l' ordine di velocità (come riportato dall'utente 1579844) dipendono dalla macchina; ecco cosa ho trovato:

a=np.empty(1e4); a.fill(5) è il più veloce;

In ordine decrescente di velocità:

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!)

Quindi, prova a scoprirlo e usa ciò che è più veloce sulla tua piattaforma.


14

avevo

numpy.array(n * [value])

in mente, ma a quanto pare è più lento di tutti gli altri suggerimenti abbastanza grandi n.

Ecco il confronto completo con perfplot (un mio progetto per animali domestici).

inserisci qui la descrizione dell'immagine

Le due emptyalternative sono ancora le più veloci (con NumPy 1.12.1). fullraggiunge grandi matrici.


Codice per generare 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,
)

7

È possibile utilizzare numpy.tile, ad esempio:

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]])

Sebbene tileabbia lo scopo di "affiancare" un array (anziché uno scalare, come in questo caso), farà il lavoro, creando array pre-riempiti di qualsiasi dimensione e dimensione.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.