2012-03-14 13 views
8

È possibile costruire una matrice numpy da una funzione? In questo caso in particolare la funzione è la differenza assoluta di due vettori: S[i,j] = abs(A[i] - B[j]). Un esempio di lavoro minimo che utilizza python regolare:Compilare la matrice numpy dalla differenza di due vettori

import numpy as np 

A = np.array([1,3,6]) 
B = np.array([2,4,6]) 
S = np.zeros((3,3)) 

for i,x in enumerate(A): 
    for j,y in enumerate(B): 
     S[i,j] = abs(x-y) 

Dare:

[[ 1. 3. 5.] 
[ 1. 1. 3.] 
[ 4. 2. 0.]] 

Sarebbe bello avere una costruzione che sembra qualcosa di simile:

def build_matrix(shape, input_function, *args) 

dove posso passare un funzione di input con i suoi argomenti e mantiene il vantaggio di velocità di numpy.

+0

Questo è possibile. Che cosa hai provato? – Marcin

+0

@Marcin - come indicato nella domanda, sto usando un semplice vecchio approccio Python per popolare la matrice in questo momento. Osservando i documenti di numpy suggeriamo che la funzione 'vectorize' potrebbe essere utile, ma non ho ancora visto come costruire la matrice dalla funzione in primo luogo. Se tu potessi indicarmi la direzione giusta (per quanto riguarda la documentazione), lo apprezzerei! – Hooked

+0

Questo dovrebbe essere possibile in plain python. Che cosa hai provato a creare la tua funzione build_matrix? Sicuramente hai qualcosa, e sei bloccato da qualche parte, piuttosto che sperare che qualcuno lo scriva tutto per te. – Marcin

risposta

10

vi consiglio di dare un'occhiata nella capacità di trasmissione di NumPy:

In [6]: np.abs(A[:,np.newaxis] - B) 
Out[6]: 
array([[1, 3, 5], 
     [1, 1, 3], 
     [4, 2, 0]]) 

http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

allora si potrebbe scrivere semplicemente la funzione come:

In [7]: def build_matrix(func,args): 
    ...:  return func(*args) 
    ...: 

In [8]: def f1(A,B): 
    ...:  return np.abs(A[:,np.newaxis] - B) 
    ...: 

In [9]: build_matrix(f1,(A,B)) 
Out[9]: 
array([[1, 3, 5], 
     [1, 1, 3], 
     [4, 2, 0]]) 

Questo dovrebbe anche essere notevolmente più veloce del tuo soluzione per array più grandi.

+0

Questo è perfetto e ha un guadagno _considerabile_ per il grande N. Vedrò di più nella trasmissione, grazie. – Hooked

+2

Per evitare di creare un array intermedio che contenga la differenza ['numpexpr'] (https://code.google.com/p/numexpr/) potrebbe essere usato:' c = a [:, None]; result = numexpr.evaluate ("abs (c - b)") ' – jfs

+0

@ J.F.Sebastian - Per quanto valga la pena, puoi anche evitarlo prendendo il valore assoluto sul posto se non hai' numexpr' installato. È leggermente più prolisso, però: 'c = a [:, None]; risultato = c - b; np.abs (risultato, risultato) ' –

13

In aggiunta a quanto suggerito da @JoshAdel, è possibile utilizzare anche lo outer method di qualsiasi numpy ufunc per eseguire la trasmissione nel caso di due array.

In questo caso, si desidera solo np.subtract.outer(A, B) (O, piuttosto, il valore assoluto di esso).

Mentre uno è abbastanza leggibile per questo esempio, in alcuni casi la trasmissione è più utile, mentre in altri i metodi ufunc sono più puliti.

In entrambi i casi, è utile conoscere entrambi i trucchi.

E.g.

import numpy as np 

A = np.array([1,3,6]) 
B = np.array([2,4,6]) 

diff = np.subtract.outer(A, B) 
result = np.abs(diff) 

In sostanza, è possibile utilizzare outer, accumulate, reduce, e reduceat con qualsiasi NumPy ufunc come subtract, multiply, divide, o anche cose come logical_and, ecc

Ad esempio, è equivalente np.cumsum a np.add.accumulate. Ciò significa che potresti implementare qualcosa come lo cumdiv entro il np.divide.accumulate se ne hai bisogno.

+0

Grazie a @JoeKington, sai in anticipo se esiste una differenza interna tra il metodo di trasmissione e il metodo esterno? Per praticità, non noto alcuna differenza di velocità per piccoli test sulla mia macchina, quindi suppongo di poter utilizzare uno dei due. – Hooked

+0

@JoeKington +1 Sicuramente un'altra grande serie di trucchi numpy per tenersi la manica. In realtà, in realtà mi piace questo approccio perché ritengo che la sintassi sia più descrittiva. – JoshAdel

+1

@talonmies Sulla mia macchina per array con 10.100.1000 e 10000 elementi, i metodi di trasmissione e quelli esterni hanno praticamente gli stessi tempi, con il metodo di trasmissione che vince di una piccola quantità. – JoshAdel

Problemi correlati