2010-05-05 4 views
5

J'ai une fonction foo qui prend un tableau NMPM en tant qu'argument et renvoie une valeur scalaire. J'ai un tableau de numpy de AxNxM data, sur lequel je voudrais carte foo pour me donner un tableau numpy résultante de longueur A.Fonctions de mappage de matrices numpy 2D

Curently, je fais ceci:

result = numpy.array([foo(x) for x in data]) 

Il fonctionne, mais il semble que je ne profite pas de la magie (et de la vitesse). Y a-t-il un meilleur moyen?

J'ai regardé numpy.vectorize, et numpy.apply_along_axis, mais aucun ne fonctionne pour une fonction de tableaux 2D.

EDIT: Je fais une régression boostée sur les correctifs d'image 24x24, donc mon AxNxM est quelque chose comme 1000x24x24. Ce que j'ai appelé foo ci-dessus applique une fonctionnalité de type Haar à un patch (donc, pas terriblement intensif en calcul).

+1

Il pourrait y avoir un moyen de recoder 'foo' afin qu'il puisse accepter un tableau numpy de dimension arbitraire, l'application de ses calculs aux deux derniers axes. Mais nous devrions voir comment 'foo' est codé pour faire des suggestions spécifiques. – unutbu

+0

J'ai ajouté plus de détails sur mon problème spécifique. Serait-il logique de laisser «data» tel quel, de recoder 'foo' pour prendre un paramètre d'index, puis de le vectoriser et de le mapper sur un' arange (len (x)) '? – perimosocordiae

Répondre

3

Si NxM est grand (disons, 100), le coût de l'itération sur A sera amorti dans pratiquement rien.

Dis la matrice est de 1000 X 100 X 100.

Itération est O (1000), mais le coût cumulé de la fonction à l'intérieur est O (1000 x 100 x 100) - 10.000 fois plus lent. (Note, ma terminologie est un peu bancale, mais je ne sais de quoi je parle)

Je ne sais pas, mais vous pouvez essayer ceci:

result = numpy.empty(data.shape[0]) 
for i in range(len(data)): 
    result[i] = foo(data[i]) 

Vous économiseriez un grand de allocation de mémoire sur la construction de la liste ... mais la surcharge de la boucle serait plus grande.

Vous pouvez également écrire une version parallèle de la boucle et la diviser en plusieurs processus. Cela pourrait être beaucoup plus rapide, en fonction de l'intensité de foo (car cela devrait compenser le traitement des données).

+4

Variation: 'résultat = np.fromiter (itertools.imap (f, données), dtype = données.dtype, compte = données.shape [0])' – jfs

1

Vous pouvez réaliser cela en remodelant votre tableau 3D en tant que tableau 2D avec la même dimension principale, et envelopper votre fonction foo avec une fonction qui fonctionne sur les tableaux 1D en les remodelant comme requis par foo. Un exemple (en utilisant trace au lieu de foo):

from numpy import * 

def apply2d_along_first(func2d, arr3d): 
    a, n, m = arr3d.shape 
    def func1d(arr1d): 
     return func2d(arr1d.reshape((n,m))) 
    arr2d = arr3d.reshape((a,n*m)) 
    return apply_along_axis(func1d, -1, arr2d) 

A, N, M = 3, 4, 5 
data = arange(A*N*M).reshape((A,N,M)) 

print data 
print apply2d_along_first(trace, data) 

Sortie:

[[[ 0 1 2 3 4] 
    [ 5 6 7 8 9] 
    [10 11 12 13 14] 
    [15 16 17 18 19]] 

[[20 21 22 23 24] 
    [25 26 27 28 29] 
    [30 31 32 33 34] 
    [35 36 37 38 39]] 

[[40 41 42 43 44] 
    [45 46 47 48 49] 
    [50 51 52 53 54] 
    [55 56 57 58 59]]] 
[ 36 116 196] 
+1

'np.fromiter (imap (' variant est 3-5 fois plus rapide que 'apply2d _ ..()' – jfs