Come copiare i dati da un array numpy a un altro


87

Qual è il modo più veloce per copiare i dati dall'array b all'array a, senza modificare l'indirizzo dell'array a. Ne ho bisogno perché una libreria esterna (PyFFTW) utilizza un puntatore al mio array che non può cambiare.

Per esempio:

a = numpy.empty(n, dtype=complex)
for i in xrange(a.size):
  a[i] = b[i]

È possibile farlo senza loop?

Risposte:


89

Credo

a = numpy.empty_like (b)
a[:] = b

farà rapidamente una copia completa. Come menzionato da Funsi, anche le versioni recenti di numpy hanno la copytofunzione.


4
+1. Ma numpy.empty non sarebbe sostanzialmente veloce di numpy.zeros ?
mg007

9
@ M.ElSaka a = bcrea semplicemente un nuovo riferimento a b. a[:] = bsignifica "imposta tutti gli elementi di auguale a quelli di b". La differenza è importante perché gli array numpy sono tipi mutabili.
Brian Hawkins

14
@ mg007 Ho eseguito alcuni test, che hanno mostrato che empty()è circa il 10% più veloce di zeros(). Sorprendentemente empty_like()è ancora più veloce. copyto(a,b)è più veloce della sintassi dell'array a[:] = b. Vedi gist.github.com/bhawkins/5095558
Brian Hawkins

2
@Brian Hawkins ha ragione. Per quando usarlo np.copyto(a, b)e quando a = b.astype(b.dtype)per un miglioramento della velocità, vedere la risposta di seguito: stackoverflow.com/a/33672015/3703716
mab

1
@michael_n Sono rimasto sorpreso empty_likeè molto più veloce di empty, soprattutto perché zeros_likeè più lento di zeros. A proposito, ho appena rieseguito il mio benchmark (ora aggiornato) e la differenza tra copyto(a,b)e a[:] = bsembra essere evaporata. gist.github.com/bhawkins/5095558
Brian Hawkins


20
a = numpy.array(b)

è persino più veloce delle soluzioni suggerite fino a numpy v1.6 e crea anche una copia dell'array. Tuttavia non ho potuto testarlo contro copyto (a, b), poiché non ho la versione più recente di numpy.


Questo è un ottimo modo per copiare un array, ma crea un nuovo oggetto. L'OP deve sapere come assegnare rapidamente i valori a un array che è già stato creato.
Brian Hawkins

15

Per rispondere alla tua domanda, ho giocato con alcune varianti e le ho profilate.

Conclusione: per copiare i dati da un array numpy a un altro usa una delle funzioni numpy integrate numpy.array(src)o numpy.copyto(dst, src)dove possibile.

(Ma scegli sempre l'ultima se dstla memoria di è già allocata, per riutilizzare la memoria. Vedi la profilazione alla fine del post.)

configurazione della profilazione

import timeit
import numpy as np
import pandas as pd
from IPython.display import display

def profile_this(methods, setup='', niter=10 ** 4, p_globals=None, **kwargs):
    if p_globals is not None:
        print('globals: {0}, tested {1:.0e} times'.format(p_globals, niter))
    timings = np.array([timeit.timeit(method, setup=setup, number=niter,
                                      globals=p_globals, **kwargs) for 
                        method in methods])
    ranking = np.argsort(timings)
    timings = np.array(timings)[ranking]
    methods = np.array(methods)[ranking]
    speedups = np.amax(timings) / timings

    pd.set_option('html', False)
    data = {'time (s)': timings,
            'speedup': ['{:.2f}x'.format(s) if 1 != s else '' for s in speedups],
            'methods': methods}
    data_frame = pd.DataFrame(data, columns=['time (s)', 'speedup', 'methods'])

    display(data_frame)
    print()

codice di profilazione

setup = '''import numpy as np; x = np.random.random(n)'''
methods = (
    '''y = np.zeros(n, dtype=x.dtype); y[:] = x''',
    '''y = np.zeros_like(x); y[:] = x''',
    '''y = np.empty(n, dtype=x.dtype); y[:] = x''',
    '''y = np.empty_like(x); y[:] = x''',
    '''y = np.copy(x)''',
    '''y = x.astype(x.dtype)''',
    '''y = 1*x''',
    '''y = np.empty_like(x); np.copyto(y, x)''',
    '''y = np.empty_like(x); np.copyto(y, x, casting='no')''',
    '''y = np.empty(n)\nfor i in range(x.size):\n\ty[i] = x[i]'''
)

for n, it in ((2, 6), (3, 6), (3.8, 6), (4, 6), (5, 5), (6, 4.5)):
    profile_this(methods[:-1:] if n > 2 else methods, setup, 
                 niter=int(10 ** it), p_globals={'n': int(10 ** n)})

risultati per Windows 7 su CPU Intel i7, CPython v3.5.0, numpy v1.10.1.


Inoltre, vedere i risultati per una variante del profilo in cui la memoria della destinazione è già pre-allocata durante la copia del valore, poiché y = np.empty_like(x)fa parte della configurazione:


Inoltre x.copy()è veloce quanto np.array(x)e mi piace molto di più la sintassi: $ python3 -m timeit -s "import numpy as np; x = np.random.random((100, 100))" "x.copy()"- 100000 loops, best of 3: 4.7 usec per loop. Ho risultati simili per np.array(x). Testato su Linux con un i5-4210U e numpy 1.10.4
Marco Sulla

Sì Marco, è piuttosto una questione di gusti personali. Ma nota che np.copyè più indulgente: np.copy(False), np.copy(None)ancora lavoro, mentre a = None; a.copy()getta AttributeError: 'NoneType' object has no attribute 'copy'. Inoltre, siamo più precisi nel dichiarare ciò che vogliamo che accada in questa riga di codice utilizzando la funzione invece della sintassi del metodo.
mab

1
Ebbene, il fatto np.copy(None)che non generi un errore è davvero poco mitico. Un motivo in più per utilizzarlo a.copy():)
Marco Sulla

1
Ho appena eseguito questi benchmark con Python 2.7.12, NumPy 1.11.2 e ho scoperto che y[:] = xora è leggermente più veloce di copyto(y, x). Codice e output su gist.github.com/bhawkins/7cdbd5b9372cb798e34e21f92279d2dc
Brian Hawkins

10

puoi usare facilmente:

b = 1*a

questo è il modo più veloce, ma ha anche alcuni problemi. Se non si definisce direttamente il dtypedi ae inoltre non si controlla il dtypedi, bsi possono avere problemi. Per esempio:

a = np.arange(10)        # dtype = int64
b = 1*a                  # dtype = int64

a = np.arange(10.)       # dtype = float64
b = 1*a                  # dtype = float64

a = np.arange(10)        # dtype = int64
b = 1. * a               # dtype = float64

Spero di poter chiarire il punto. A volte cambierai il tipo di dati con una piccola operazione.


1
No. In questo modo viene creato un nuovo array. È equivalente a b = a.copy ().
Charles Brunet

scusa, ma non ti capisco. Cosa intendi con creare un nuovo array? Tutti gli altri metodi qui presentati hanno lo stesso comportamento.a = numpy.zeros(len(b))o a = numpy.empty(n,dtype=complex)creerà anche un nuovo array.
ahelm

2
Supponi di avere a = numpy.empty (1000). Ora, è necessario riempire un con i dati, senza modificarne l'indirizzo in memoria. Se si esegue un [0] = 1, non si ricrea un array, si cambia solo il contenuto dell'array.
Charles Brunet

1
@CharlesBrunet l'array dovrà essere creato ad un certo punto. Questo intelligente one-liner fa tutto in un'unica operazione.
heltonbiker

7

Ci sono molte cose diverse che puoi fare:

a=np.copy(b)
a=np.array(b) # Does exactly the same as np.copy
a[:]=b # a needs to be preallocated
a=b[np.arange(b.shape[0])]
a=copy.deepcopy(b)

Cose che non funzionano

a=b
a=b[:] # This have given my code bugs 

2

Perché non usare

a = 0 + b

Penso che sia simile alla moltiplicazione precedente ma potrebbe essere più semplice.

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.