2015-05-04 7 views
6

Sto facendo una sommatoria abbastanza complicata usando una matrice con numpy. La forma della matrice è matrix.shape = (500, 500) e la forma dell'array è arr.shape = (25,). Il funzionamento è il seguente:Make numpy.sum() restituisce una somma di matrici anziché un singolo numero

totalsum = np.sum([i * matrix for i in arr]) 

Ecco quello che non capisco:

np.sum() è molto lento e restituisce un singolo galleggiante, float64. Facendo la stessa operazione con Python sum.(), cioè

totalsum2 = sum([i*matrix for i in arr]) 

preserva la forma della matrice. Cioè, la forma risultante è totalsum2.shape() = (500, 500). Eh?

Penso anche che sia strano che np.sum() impieghi più tempo di sum(), in particolare quando stiamo lavorando con numpy ndarrays.

Che cosa sta succedendo esattamente qui? In che modo np.sum() somma i valori sopra riportati rispetto a sum()?

Desidero np.sum() per mantenere la forma della matrice. Come posso impostare le dimensioni in modo che np.sum() mantenga le dimensioni della matrice e non restituisca un singolo float?

+1

Questa operazione deve essere semplicemente scritta come 'np.sum (arr) * matrice '. – Daniel

+0

@Ophion la matrice e la matrice non hanno la stessa forma. Voglio moltiplicare l'intera matrice per ogni valore nella matrice. Quindi, voglio sommare tutte le matrici risultanti. – JesseTrevve

+0

Questo può essere scritto nella notazione einsum come 'np.einsum (" k, ij-> ij ", arr, matrix)'. Come si può vedere non ci sono indici comuni tra tensori. Puoi verificare tu stesso calcolando uno dei metodi sopra indicati e la risposta che hai selezionato come corretta. – Daniel

risposta

5

È necessario chiamare np.sommare con il parametro opzionale asse impostato su 0 (sommatoria sopra l'asse 0, cioè quello creato da lista la vostra comprensione)

totalsum = np.sum([i * matrix for i in arr], 0) 

In alternativa, è possibile omettere le staffe in modo np.sum valutare un generatore.

totalsum = np.sum(i * matrix for i in arr) 
+1

Lasciando il parametro dell'asse = 0, è piuttosto "la somma sopra l'asse 0" piuttosto che "nessuna sommatoria" sull'asse. Funziona perché la comprensione delle liste usate crea efficacemente una struttura di dati tridimensionale, il cui primo asse (0 °) come quello di Numpy è la dimensione creata "impilando" tutte le copie della 'matrice moltiplicata'. – jsbueno

2
[i*matrix for i in arr] # list of matrices 

L'elenco precedente è un elenco di matrici, quindi quando si utilizza la somma, verranno aggiunti gli array.

In [6]: matrix = np.array([[1,2],[3,4]]) 

In [7]: matrix 
Out[7]: 
array([[1, 2], 
     [3, 4]]) 


In [9]: [i * matrix for i in (2,4,8)] 
Out[9]: 
[array([[2, 4], 
     [6, 8]]), array([[ 4, 8], 
     [12, 16]]), array([[ 8, 16], 
     [24, 32]])] 

Si prega di consultare la Guida per np.sum

File:  /home/ale/.virtualenvs/ml/local/lib/python2.7/site-packages/numpy/core/fromnumeric.pyaxis=None, dtype=None, out=None, keepdims=False) Docstring: Sum of array elements over a given axis. 

Parameters 
---------- a : array_like 
    Elements to sum. axis : None or int or tuple of ints, optional 
    Axis or axes along which a sum is performed. 
    The default (`axis` = `None`) is perform a sum over all 
    the dimensions of the input array. `axis` may be negative, in 
    which case it counts from the last to the first axis. 

    .. versionadded:: 1.7.0 

Si dice che se non si definisce un asse sarà sommare tutte le dimensioni. Esempio:

In [4]: np.sum(np.array([[1,2],[3,4]])) # 1 + 2 + 3 + 4... 
Out[4]: 10 

Perché è necessario più tempo per np.sum? ben intuizione dice che nell'espressione [i*matrix for i in arr] si sta creando un nuovo array per ogni i che quindi np.sum somma su tutti gli array.

Potrebbe esserci un altro motivo, ma suppongo che sia così.

+0

Ho provato a correggere le matrici/matrici, ma hai anche apportato delle modifiche, quindi spero di aver impostato la risposta sull'ultima modifica. – Paul

+0

Grazie a @Paul per le modifiche. – Ale

+1

@Ale Numpy prima costruisce tutti gli array di 'i * matrix', quindi quando' np.sum' viene chiamato build a 3D array dalla lista di array. L'overhead è tutta la copia extra in memoria. – Daniel

4

Il task sum() regolare di Python sta prendendo tutti gli elementi in tale elenco e sommandoli. Quando si aggiungono matrici della stessa dimensione, basta aggiungerle elementwise. Per esempio:

test1 = np.array([[4,3],[2,1]]) 
test2 = np.array([[8,9],[1,1]]) 
print test1 + test2 

Returns

[[12,12] 
[3,2]] 

Mentre con np.sum, si sta aggiungendo lungo un asse o gli assi. Se si desidera mantenere le cose in un array e si desidera utilizzare np.sum, si vorrà proiettare l'operazione (moltiplicata per i in array) in una terza dimensione e quindi utilizzare np.sum (axis = 2) .

questo può essere fatto utilizzando:

np.sum(matrix[:,:,np.newaxis] * array[np.newaxis,np.newaxis,:],axis=2) 
+0

Funziona semplicemente facendo passare "axis = 0" alla chiamata di O.P.: la sua comprensione crea una struttura di dati tridimensionale dal quale il primo asse è quello desiderato. – jsbueno

+0

Tom: @jsbueno è corretto. Passare "axis = 0" dà totalsum.shape = (500, 500). Passando "axis = 2" si dà totalsum.shape = (24, 500). – JesseTrevve

+0

Sì, l'asse = 0 è ciò che si desidera utilizzare se si fanno le cose tramite il metodo di Yoann. E, sulla base di alcuni test rapidi che ho fatto, questo è il metodo che vuoi usare se sei limitato nel tempo di calcolo. Per l'esempio che ho mostrato, tuttavia, è necessario utilizzare axis = 2. In alternativa, è possibile riorganizzare le posizioni np.newaxis per rendere l'asse = 0 quello che si desidera sommare. – Tom