2013-08-21 16 views
7

mam numpy tablicę kształcie:Get znaczy 2D plasterka tablicy 3D w numpy

(11L, 5L, 5L) 

Chcę obliczyć średnią ponad 25 elementów każdego „plaster” tablicy [ 0,:,:], [1,:,:] itd., Zwracając 11 wartości.

Wydaje się to głupie, ale nie mogę się dowiedzieć, jak to zrobić. Myślałem, że funkcja mean(axis=x) to zrobi, ale wypróbowałem wszystkie możliwe kombinacje osi i żadne z nich nie dało mi pożądanego wyniku.

Oczywiście mogę to zrobić za pomocą pętli for i krojenia, ale na pewno jest lepszy sposób?

Odpowiedz

11

Użyj krotki dla osi:

>>> a = np.arange(11*5*5).reshape(11,5,5) 
>>> a.mean(axis=(1,2)) 
array([ 12., 37., 62., 87., 112., 137., 162., 187., 212., 
     237., 262.]) 

Edytuj: This wor ks tylko z numpy w wersji 1.7+.

+2

To działa? Można by tak myśleć o 1.7 i później, ale doktorzy wciąż mówią tylko jedną oś. – Jaime

+1

Nie myślałem o wersji numpy, mam 1.7.1 i działa. Nie ma go w dokumentacji, ale dziennik zmian mówi o ufuncs: http://www.softpedia.com/progChangelog/Numpy-Changelog-103892.html –

+2

Fajnie, nie wiedziałem, że to zostało dodane! – lmjohns3

4

Można reshape(11, 25) a następnie zadzwonić mean tylko raz (szybciej):

a.reshape(11, 25).mean(axis=1) 

Alternatywnie, można zadzwonić np.mean dwukrotnie (około 2x wolniej na moim komputerze):

a.mean(axis=2).mean(axis=1) 
+1

myślę, że to jest odpowiedź najprostsza, choć einsum wydaje się szybsze. – lmjohns3

5

zawsze można użyć np.einsum:

>>> a = np.arange(11*5*5).reshape(11,5,5) 
>>> np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2]) 
array([ 12, 37, 62, 87, 112, 137, 162, 187, 212, 237, 262]) 

Works na wyższych tablic wymiarowych (wszystkie z tych metod byłoby gdyby etykiety osi są zmienione):

>>> a = np.arange(10*11*5*5).reshape(10,11,5,5) 
>>> (np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2])).shape 
(10, 11) 

Szybciej do bagażnika:

a = np.arange(11*5*5).reshape(11,5,5) 

%timeit a.reshape(11, 25).mean(axis=1) 
10000 loops, best of 3: 21.4 us per loop 

%timeit a.mean(axis=(1,2)) 
10000 loops, best of 3: 19.4 us per loop 

%timeit np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2]) 
100000 loops, best of 3: 8.26 us per loop 

Skaluje się nieco lepiej niż inne metody w miarę wzrostu rozmiaru tablicy.

Korzystanie dtype=np.float64 ma znacznie nie zmieni powyższe czasy, więc po prostu do podwójnego sprawdzenia:

a = np.arange(110*50*50,dtype=np.float64).reshape(110,50,50) 

%timeit a.reshape(110,2500).mean(axis=1) 
1000 loops, best of 3: 307 us per loop 

%timeit a.mean(axis=(1,2)) 
1000 loops, best of 3: 308 us per loop 

%timeit np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2]) 
10000 loops, best of 3: 145 us per loop 

również coś, co jest ciekawe:

%timeit np.sum(a) #37812362500.0 
100000 loops, best of 3: 293 us per loop 

%timeit np.einsum('ijk->',a) #37812362500.0 
100000 loops, best of 3: 144 us per loop 
+1

Myślę, że prędkość pochodzi z twojego połączenia do 'np.einsum' przy użyciu' inc' akumulatora, zamiast 'float' lub' double', nie wiesz, że używa 'np.mean'. Jest to ryzykowne, jeśli chodzi o statystyki obliczeniowe, ponieważ można przepełnić akumulator i uzyskać bardzo złe wyniki. Nadanie 'np.einsum' a' dtype = np.float' lub 'dtype = np.double' zarówno sprawi, że obliczenia będą bardziej niezawodne, jak i (domyślam się tutaj) bardziej podobne w działaniu do standardowych funkcji. Ale 'np.einsum' jest nadal super fajną funkcją, więc dostajesz +1 ... – Jaime

+0

@Jamie. Taka była moja myśl, ale w moim wstępnym testowaniu pokazałem, że 'einsum' było rzeczywiście szybsze dla każdego rozmiaru i dtype.Zaktualizowałem post z czasami 'np.double'. – Daniel

+0

@Ophion ... to dziwne, że 'sum()' nie daje tej samej prędkości co 'einsum()' ... bardzo dobrze obserwowane ... faktycznie drugą szybszą metodą obliczenia średniej byłoby: 'timeit a.sum (axis = (1,2))/a.shape [-1]/a.shape [-2] ' –