2016-06-10 18 views
7

In questo caso l'utilizzo di oggetti come numpy.r_ o numpy.c_ è migliore (più efficiente, più adatto) rispetto all'utilizzo di funzioni come concatenate o vstack, ad esempio?python perché usare numpy.r_ invece di concatenare

Sto cercando di capire un codice in cui il programmatore ha scritto qualcosa come:

return np.r_[0.0, 1d_array, 0.0] == 2 

dove 1d_array è un array i cui valori possono essere 0, 1 o 2. Perché non utilizzare np.concatenate (ad esempio) anziché ? Come:

return np.concatenate([[0.0], 1d_array, [0.0]]) == 2 

È più leggibile e apparentemente fa la stessa cosa.

+0

solo una comodità di notazione. 'np.r_ [1: 5, 3: 7]' versus 'np.concatenate (np.arange (....)'. Stessa velocità.Tutto finisce come una chiamata 'concatenata'. – hpaulj

+0

Il codice completo è in https://github.com/numpy/numpy/blob/master/numpy/lib/index_tricks.py. 'r_' è un oggetto' AxisConcatenator' .Lettura istruttiva – hpaulj

risposta

9

np.r_ è implementato nel file numpy/lib/index_tricks.py. Questo è puro codice Python, senza materiale speciale compilato. Quindi non sarà più veloce dell'equivalente scritto con concatenate, arange e linspace. È utile solo se la notazione si adatta al tuo modo di pensare e alle tue esigenze.

Nel tuo esempio solo salva la conversione dei scalari di liste o matrici:

In [452]: np.r_[0.0, np.array([1,2,3,4]), 0.0] 
Out[452]: array([ 0., 1., 2., 3., 4., 0.]) 

errore gli stessi argomenti:

In [453]: np.concatenate([0.0, np.array([1,2,3,4]), 0.0]) 
... 
ValueError: zero-dimensional arrays cannot be concatenated 

corretto con l'aggiunta []

In [454]: np.concatenate([[0.0], np.array([1,2,3,4]), [0.0]]) 
Out[454]: array([ 0., 1., 2., 3., 4., 0.]) 

hstack si occupa di ciò passando tutti gli argomenti tramite [atleast_1d(_m) for _m in tup]:

In [455]: np.hstack([0.0, np.array([1,2,3,4]), 0.0]) 
Out[455]: array([ 0., 1., 2., 3., 4., 0.]) 

Così almeno nei casi più semplici è più simile a hstack.

Ma la vera utilità di r_ arriva quando si desidera utilizzare le gamme

np.r_[0.0, 1:5, 0.0] 
np.hstack([0.0, np.arange(1,5), 0.0]) 
np.r_[0.0, slice(1,5), 0.0] 

r_ consente di utilizzare la sintassi : che viene utilizzato in indicizzazione. Questo perché in realtà è un'istanza di una classe che ha un metodo __getitem__. index_tricks utilizza questo trucco di programmazione più volte.

Hanno gettato in altre campane-n-fischi

Utilizzando un imaginary passo, utilizza np.linspace per espandere la fetta piuttosto che np.arange.

np.r_[-1:1:6j, [0]*3, 5, 6] 

produce:

array([-1. , -0.6, -0.2, 0.2, 0.6, 1. , 0. , 0. , 0. , 5. , 6. ]) 

Non ci sono ulteriori dettagli nella documentazione.

Ho fatto alcuni test di tempo per tante fette in https://stackoverflow.com/a/37625115/901925

3

Tutta la spiegazione è necessario:

https://sourceforge.net/p/numpy/mailman/message/13869535/

ho trovato la parte più rilevante di essere:

""" 
For r_ and c_ I'm summarizing, but effectively they seem to be doing 
something like: 

r_[args]: 
    concatenate(map(atleast_1d,args),axis=0) 

c_[args]: 
    concatenate(map(atleast_1d,args),axis=1) 

c_ behaves almost exactly like hstack -- with the addition of range 
literals being allowed. 

r_ is most like vstack, but a little different since it effectively 
uses atleast_1d, instead of atleast_2d. So you have 
>>> numpy.vstack((1,2,3,4)) 
array([[1], 
     [2], 
     [3], 
     [4]]) 
but 
>>> numpy.r_[1,2,3,4] 
array([1, 2, 3, 4]) 
""" 
+2

Dovresti almeno descrivere il contenuto di quella pagina, incase il collegamento ipertestuale si interrompe – dodell

+0

@dodell equo sufficiente – piRSquared

+2

Penso che il confronto tra 'r_' e' c_' in 'vstack' e' hstack' sia fuorviante, anche sbagliato. Nel caso di '1,2,3,4' il 4 operazioni producono forme (4,), (1,4), (4,1), (4,) rispettivamente: in questo semplice caso 'r_' e' hstack' producono la stessa cosa, e 'c_' e' vstack 'sono la trasposizione l'uno dell'altro. – hpaulj

1

ero interessato a questa domanda anche e confrontato la velocità di

numpy.c_[a, a] 
numpy.stack([a, a]).T 
numpy.vstack([a, a]).T 
numpy.column_stack([a, a]) 
numpy.concatenate([a[:,None], a[:,None]], axis=1) 

cui tutti fanno la stessa cosa per qualsiasi vettore di input a . Ecco quello che ho trovato (usando perfplot):

enter image description here

Per i numeri più piccoli, numpy.concatenate è il vincitore, per i più grandi (da circa 3000) stack/vstack.


La trama è stato creato con

import numpy 
import perfplot 

perfplot.show(
    setup=lambda n: numpy.random.rand(n), 
    kernels=[ 
     lambda a: numpy.c_[a, a], 
     lambda a: numpy.stack([a, a]).T, 
     lambda a: numpy.vstack([a, a]).T, 
     lambda a: numpy.column_stack([a, a]), 
     lambda a: numpy.concatenate([a[:, None], a[:, None]],axis=1) 
     ], 
    labels=['c_', 'stack', 'vstack', 'column_stack', 'concat'], 
    n_range=[2**k for k in range(19)], 
    xlabel='len(a)', 
    ) 
Problemi correlati