2013-02-17 8 views
11

Sto cercando una formulazione veloce per eseguire un binning numerico di un array numpy 2D. Con binning intendo calcolare le medie della submatrix oi valori cumulativi. Per es. x = numpy.arange (16) .reshape (4, 4) sarebbe stato diviso in 4 submatrix di 2x2 ciascuno e restituisce numpy.array ([[2.5.4.5], [10.5,12.5]]) in cui 2.5 = numpy. media ([0,1,4,5]) ecc ...Numpy rebinning a array 2D

Come eseguire un'operazione del genere in modo efficiente ... Non ho proprio idea di come eseguire questa operazione ...

Molte grazie ...

+0

Sono le sottomatrici sono garantiti per adattarsi, esattamente? hai numpy 1.7. disponibile (è semplicemente pulito, non necessario)? – seberg

+0

I have numpy 1.8dev ma il mio lavoro diventa versione precedente ... – user1187727

risposta

17

È possibile utilizzare una vista di dimensione superiore della matrice e prendere la media lungo le dimensioni extra:

In [12]: a = np.arange(36).reshape(6, 6) 

In [13]: a 
Out[13]: 
array([[ 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]]) 

In [14]: a_view = a.reshape(3, 2, 3, 2) 

In [15]: a_view.mean(axis=3).mean(axis=1) 
Out[15]: 
array([[ 3.5, 5.5, 7.5], 
     [ 15.5, 17.5, 19.5], 
     [ 27.5, 29.5, 31.5]]) 

In generale, se si vuole bidoni di forma (a, b) per una serie di (rows, cols), la vostra rimodellamento di esso dovrebbe essere .reshape(rows // a, a, cols // b, b). Si noti inoltre che l'ordine di .mean è importante, ad es. a_view.mean(axis=1).mean(axis=3) genererà un errore, perché a_view.mean(axis=1) ha solo tre dimensioni, anche se a_view.mean(axis=1).mean(axis=2) funzionerà correttamente, ma rende più difficile capire cosa sta succedendo.

Come è, il codice di cui sopra funziona solo se è possibile montare un numero intero di cassonetti all'interno dell'array, vale a dire se a divide rows e b divide cols. Ci sono modi per gestire altri casi, ma dovrai definire il comportamento che desideri.

+4

On numpy 1.7. puoi schiacciare insieme in '.mean (axis = (1,3))'! – seberg

+1

Non sapevo che questo rimodellamento sarebbe stato possibile, fantastico! Sfortunatamente, la media è ordinata in base a come ottenere la media di ex. una sottostratrice di 2,2 nell'esempio (intendo l'angolo 0,1,6,7 ecc ...)? – user1187727

+1

@ user1187727 Non penso di capire la tua domanda, ma la media di '[[0, 1], [6, 7]]' è item '[0, 0]' di 'a_view.mean (axis = 3) .mean (asse = 1) '. – Jaime

0

presumo che si desidera solo per sapere come costruire in generale una funzione che si comporta bene e fa qualcosa con gli array, proprio come numpy.reshape nel tuo esempio. Quindi se le prestazioni contano davvero e stai già usando Numpy, puoi scrivere il tuo codice C per quello, come fa Numpy. Ad esempio, l'implementazione di arange è completamente in C. Quasi tutto ciò che conta in termini di prestazioni è implementato in C.

Tuttavia, prima di farlo, dovresti provare a implementare il codice in python e vedere se le prestazioni è abbastanza buono Prova a rendere il codice Python il più efficiente possibile. Se ancora non soddisfa le tue esigenze di prestazioni, vai nel modo C.

Si può leggere su questo nello docs.

1

See the SciPy Cookbook on rebinning, che fornisce questo frammento:

def rebin(a, *args): 
    '''rebin ndarray data into a smaller ndarray of the same rank whose dimensions 
    are factors of the original dimensions. eg. An array with 6 columns and 4 rows 
    can be reduced to have 6,3,2 or 1 columns and 4,2 or 1 rows. 
    example usages: 
    >>> a=rand(6,4); b=rebin(a,3,2) 
    >>> a=rand(6); b=rebin(a,2) 
    ''' 
    shape = a.shape 
    lenShape = len(shape) 
    factor = asarray(shape)/asarray(args) 
    evList = ['a.reshape('] + \ 
      ['args[%d],factor[%d],'%(i,i) for i in range(lenShape)] + \ 
      [')'] + ['.sum(%d)'%(i+1) for i in range(lenShape)] + \ 
      ['/factor[%d]'%i for i in range(lenShape)] 
    print ''.join(evList) 
    return eval(''.join(evList))