2011-11-10 17 views
35

Sto usando Numpy per memorizzare i dati in matrici. Venendo da sfondo R, c'è stato un modo estremamente semplice per applicare una funzione su righe/colonne o entrambe le matrici.Applicazione funzione su matrice/riga matrice numpy

C'è qualcosa di simile per la combinazione python/numpy? Non è un problema scrivere la mia piccola implementazione, ma mi sembra che la maggior parte delle versioni che creerò saranno significativamente meno efficienti/più dispendiose in termini di memoria rispetto a qualsiasi implementazione esistente.

Vorrei evitare di copiare dalla matrice numpy a una variabile locale, ecc., È possibile?

Le funzioni che sto tentando di implementare sono principalmente semplici confronti (ad esempio quanti elementi di una determinata colonna sono più piccoli del numero x o quanti di essi hanno un valore assoluto maggiore di y).

+2

Inserire un codice di esempio con l'output desiderato. Dal tuo elogio della risposta di unutbu, sembra che quello che vuoi sia molto diretto, ma per ora è troppo astratto per chiunque possa darti consigli utili, penso. – heltonbiker

risposta

43

Quasi tutte le funzioni di Numpy operano su interi array e/o può essere detto di operare su un particolare asse (riga o colonna).

Finché è possibile definire la funzione in termini di funzioni di numpy che agiscono su array numpy o sezioni di array, la funzione funzionerà automaticamente su intere matrici, righe o colonne.

Potrebbe essere più utile chiedere come implementare una particolare funzione per ottenere consigli più concreti.


Numpy fornisce np.vectorize e np.frompyfunc per attivare funzioni Python che operano su numeri in funzioni che operano su array numpy.

Ad esempio,

def myfunc(a,b): 
    if (a>b): return a 
    else: return b 
vecfunc = np.vectorize(myfunc) 
result=vecfunc([[1,2,3],[5,6,9]],[7,4,5]) 
print(result) 
# [[7 4 5] 
# [7 6 9]] 

(Gli elementi del primo array ottenere sostituito dal corrispondente elemento della seconda matrice quando il secondo è più grande.)

Ma non troppo eccitato; np.vectorize e np.frompyfunc sono just syntactic sugar. In realtà non rendono il tuo codice più veloce. Se la funzione Python sottostante funziona su un valore alla volta, allora np.vectorize lo alimenterà un elemento alla volta e l'intera operazione sarà piuttosto lenta (rispetto all'uso di una funzione numpy che chiama alcuni C o Fortran sottostanti implementazione).


contare quanti elementi della colonna x sono più piccole di un numero y, si potrebbe usare un'espressione come:

(array['x']<y).sum() 

Ad esempio:

import numpy as np 
array=np.arange(6).view([('x',np.int),('y',np.int)]) 
print(array) 
# [(0, 1) (2, 3) (4, 5)] 

print(array['x']) 
# [0 2 4] 

print(array['x']<3) 
# [ True True False] 

print((array['x']<3).sum()) 
# 2 
+0

Quindi non esiste un modo semplice per eseguire una funzione generica? (solo curioso, in generale le funzioni di numpy dovrebbero essere sufficienti - ho solo bisogno di fare semplici confronti, per esempio quanti elementi di una colonna x sono più piccoli del numero y) – petr

+0

Sembra che tu possa fare questo genere di cose con le fette. – wim

+0

Grazie mille! .. quindi se faccio array ['x'] <3, questo è gestito dall'implementazione più veloce di numpy rispetto alla mia funzione vettoriale? – petr

14

elementi selezione da un array NumPy basato su una o più condizioni è diretto usando la sintassi densamente sintetica di NumPy:

>>> import numpy as NP 
>>> # generate a matrix to demo the code 
>>> A = NP.random.randint(0, 10, 40).reshape(8, 5) 
>>> A 
    array([[6, 7, 6, 4, 8], 
     [7, 3, 7, 9, 9], 
     [4, 2, 5, 9, 8], 
     [3, 8, 2, 6, 3], 
     [2, 1, 8, 0, 0], 
     [8, 3, 9, 4, 8], 
     [3, 3, 9, 8, 4], 
     [5, 4, 8, 3, 0]]) 


quanti elementi nella colonna 2 sono maggiori di 6?

>>> ndx = A[:,1] > 6 
>>> ndx 
     array([False, True, False, False, True, True, True, True], dtype=bool) 
>>> NP.sum(ndx) 
     5 


quanti elementi in ultima colonna di A hanno un valore assoluto maggiore di 3?

>>> A = NP.random.randint(-4, 4, 40).reshape(8, 5) 
>>> A 
    array([[-4, -1, 2, 0, 3], 
     [-4, -1, -1, -1, 1], 
     [-1, -2, 2, -2, 3], 
     [ 1, -4, -1, 0, 0], 
     [-4, 3, -3, 3, -1], 
     [ 3, 0, -4, -1, -3], 
     [ 3, -4, 0, -3, -2], 
     [ 3, -4, -4, -4, 1]]) 

>>> ndx = NP.abs(A[:,-1]) > 3 
>>> NP.sum(ndx) 
     0 


quanti elementi nelle prime due righe di A sono superiori o uguali a 2?

>>> ndx = A[:2,:] >= 2 
>>> NP.sum(ndx.ravel()) # 'ravel' just flattens ndx, which is originally 2D (2x5) 
     2 

sintassi indicizzazione NumPy è abbastanza vicino alla R; dato il vostro fluidità in R, qui sono le differenze principali tra R e NumPy in questo contesto:

NumPy indici sono base zero, in R, indicizzazione inizia con 1

NumPy (come Python) consente di indice da destra a sinistra utilizzando indici negativi - ad esempio,

# to get the last column in A 
A[:, -1], 

# to get the penultimate column in A 
A[:, -2] 

# this is a big deal, because in R, the equivalent expresson is: 
A[, dim(A)[0]-2] 

NumPy utilizza colon ":" notazione per indicare "unsliced", ad es. In R, a ottenere le prime tre righe in A, si utilizzerà, A [1: 3,]. In NumPy, si userebbe un [0: 2,:] (in NumPy, la "0" non è necessario, infatti è preferibile utilizzare un [: 2,:]

+0

grazie, ho notato che l'indirizzo di array di Numpy prima, comunque, è sempre bello avere un buon sommario :) – petr

6

ho anche venire da uno sfondo più R, e urtato nella mancanza di un'applicazione più versatile che potrebbe prendere funzioni brevi personalizzate.Ho visto il forum suggerendo l'uso di funzioni numpy di base perché molti di loro gestiscono gli array.Tuttavia, mi sono confuso sul le funzioni numpy "native" gestiscono l'array (a volte 0 è row-wise e 1 column-wise, a volte il contrario)

La mia soluzione personale a funzioni più flessibili con apply_along_axis era combinarle con le funzioni lambda implicite disponibili in python Le funzioni Lambda dovrebbero essere molto facili da capire per chi ha la mente che usa uno stile di programmazione più funzionale, come nelle funzioni R, si applica, tranquillamente, lapply, ecc.

Quindi, per esempio, volevo applicare la standardizzazione delle variabili in una matrice. Tipicamente in R c'è una funzione per questo (scala), ma si può anche costruire facilmente con applica:

(codice R)

apply(Mat,2,function(x) (x-mean(x))/sd(x)) 

Si vede come il corpo della funzione si applica all'interno (x-media (x))/sd (x) è il bit che non possiamo digitare direttamente per python apply_along_axis.Con lambda questo è facile da implementare per un insieme di valori, in modo da:

(Python)

import numpy as np 
vec=np.random.randint(1,10,10) # some random data vector of integers 

(lambda x: (x-np.mean(x))/np.std(x) )(vec) 

Poi, tutti abbiamo bisogno è di collegare questo all'interno del pitone applicare e passare la matrice di interesse attraverso apply_along_axis

Mat=np.random.randint(1,10,3*4).reshape((3,4)) # some random data vector 
np.apply_along_axis(lambda x: (x-np.mean(x))/np.std(x),0,Mat) 

Ovviamente, la funzione lambda potrebbe essere implementata come una funzione separata, ma immagino il punto è quello di utilizzare piuttosto piccole funzioni contenute all'interno della linea in cui si applicano origine.

Spero che lo trovi utile!