2015-03-14 16 views
5

Desidero selezionare determinati elementi di una matrice ed eseguire un calcolo della media ponderata in base ai valori. Tuttavia, utilizzando una condizione di filtro, distrugge la struttura originale dell'array. arr che era di forma (2, 2, 3, 2) viene trasformato in un array 1-dimensionale. Questo non serve a me, poiché non tutti questi elementi devono essere combinati in seguito l'uno con l'altro (ma sottoinsiemi di essi). Come posso evitare questo appiattimento?Perdita della dimensione della matrice di Numpy durante il mascheramento

>>> arr = np.asarray([ [[[1, 11], [2, 22], [3, 33]], [[4, 44], [5, 55], [6, 66]]], [ [[7, 77], [8, 88], [9, 99]], [[0, 32], [1, 33], [2, 34] ]] ]) 
>>> arr 
array([[[[ 1, 11], 
     [ 2, 22], 
     [ 3, 33]], 

     [[ 4, 44], 
     [ 5, 55], 
     [ 6, 66]]], 


     [[[ 7, 77], 
     [ 8, 88], 
     [ 9, 99]], 

     [[ 0, 32], 
     [ 1, 33], 
     [ 2, 34]]]]) 
>>> arr.shape 
(2, 2, 3, 2) 
>>> arr[arr>3] 
array([11, 22, 33, 4, 44, 5, 55, 6, 66, 7, 77, 8, 88, 9, 99, 32, 33, 
     34]) 
>>> arr[arr>3].shape 
(18,) 
+1

Elaborate sul calcolo di cui avete bisogno fare con questi valori. Come useresti la struttura 'arr'? – hpaulj

risposta

5

Checkout numpy.where

http://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html

Per mantenere la stessa dimensionalità che si sta per bisogno di un valore di riempimento. Nell'esempio che segue che uso 0, ma si potrebbe anche usare np.nan

np.where(arr>3, arr, 0) 

rendimenti

array([[[[ 0, 11], 
     [ 0, 22], 
     [ 0, 33]], 

     [[ 4, 44], 
     [ 5, 55], 
     [ 6, 66]]], 


     [[[ 7, 77], 
     [ 8, 88], 
     [ 9, 99]], 

     [[ 0, 32], 
     [ 0, 33], 
     [ 0, 34]]]]) 
+0

Questo è quello che stavo cercando. – orange

3

Guardate arr>3:

In [71]: arr>3 
Out[71]: 
array([[[[False, True], 
     [False, True], 
     [False, True]], 

     [[ True, True], 
     [ True, True], 
     [ True, True]]], 


     [[[ True, True], 
     [ True, True], 
     [ True, True]], 

     [[False, True], 
     [False, True], 
     [False, True]]]], dtype=bool) 

arr[arr>3] seleziona quegli elementi in cui la maschera è True. Che tipo di struttura o forma vuoi che abbia questa selezione? Flat è l'unica cosa che ha senso, no? arr non viene modificato.

Si potrebbe azzerare i termini che non si adattano la maschera,

In [84]: arr1=arr.copy() 
In [85]: arr1[arr<=3]=0 
In [86]: arr1 
Out[86]: 
array([[[[ 0, 11], 
     [ 0, 22], 
     [ 0, 33]], 

     [[ 4, 44], 
     [ 5, 55], 
     [ 6, 66]]], 


     [[[ 7, 77], 
     [ 8, 88], 
     [ 9, 99]], 

     [[ 0, 32], 
     [ 0, 33], 
     [ 0, 34]]]]) 

Ora si potrebbe fare somme di peso o medie su varie dimensioni.

np.nonzero (o np.where) potrebbe anche essere utile, fornendo gli indici dei termini selezionati:

In [88]: np.nonzero(arr>3) 
Out[88]: 
(array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]), 
array([0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1]), 
array([0, 1, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 1, 2]), 
array([1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1])) 
5

Si potrebbe considerare l'utilizzo di un np.ma.masked_array per rappresentare il sottoinsieme di elementi che soddisfano la sua condizione:

import numpy as np 

arr = np.asarray([[[[1, 11], [2, 22], [3, 33]], 
        [[4, 44], [5, 55], [6, 66]]], 
        [[[7, 77], [8, 88], [9, 99]], 
        [[0, 32], [1, 33], [2, 34]]]]) 

masked_arr = np.ma.masked_less(arr, 3) 

print(masked_arr) 
# [[[[-- 11] 
# [-- 22] 
# [3 33]] 

# [[4 44] 
# [5 55] 
# [6 66]]] 


# [[[7 77] 
# [8 88] 
# [9 99]] 

# [[-- 32] 
# [-- 33] 
# [-- 34]]]] 

Come si può vedere, l'array mascherato mantiene le sue dimensioni originali. È possibile accedere rispettivamente ai dati sottostanti e alla maschera tramite gli attributi .data e .mask. Maggior parte delle funzioni NumPy non tener conto di valori mascherati, ad esempio:

# mean of whole array 
print(arr.mean()) 
# 26.75 

# mean of non-masked elements only 
print(masked_arr.mean()) 
# 33.4736842105 

Il risultato di un'operazione elemento saggio su un array mascherato e una matrice non mascherato anche preservare i valori della maschera:

masked_arrsum = masked_arr + np.random.randn(*arr.shape) 

print(masked_arrsum) 
# [[[[-- 11.359989067421582] 
# [-- 23.249092437269162] 
# [3.326111354088174 32.679132708120726]] 

# [[4.289134334263137 43.38559221094378] 
# [6.028063054523145 53.5043991898567] 
# [7.44695154979811 65.56890530368757]]] 


# [[[8.45692625294376 77.36860675985407] 
# [5.915835159196378 87.28574554110307] 
# [8.251106168209688 98.7621940026713]] 

# [[-- 33.24398289945855] 
# [-- 33.411941757624284] 
# [-- 34.964817895873715]]]] 

la somma viene calcolata solo sui valori non mascherati di masked_arr - si può vedere questo, cercando in masked_sum.data:

print(masked_sum.data) 
# [[[[ 1.   11.35998907] 
# [ 2.   23.24909244] 
# [ 3.32611135 32.67913271]] 

# [[ 4.28913433 43.38559221] 
# [ 6.02806305 53.50439919] 
# [ 7.44695155 65.5689053 ]]] 


# [[[ 8.45692625 77.36860676] 
# [ 5.91583516 87.28574554] 
# [ 8.25110617 98.762194 ]] 

# [[ 0.   33.2439829 ] 
# [ 1.   33.41194176] 
# [ 2.   34.9648179 ]]]] 
+0

Interessante. Pensavo che "arr [arr <3]" avrebbe implicitamente creato un array mascherato - imparato qualcosa di nuovo (+1). – orange

+1

Ricorda che 'arr <3' è solo un array booleano, e l'indicizzazione con un array booleano restituirà sempre quegli elementi in' arr' dove l'indice booleano è 'True'. Per curiosità, perché hai scelto di andare con 'np.where' alla fine? Delle tre risposte sembra il modo meno diretto per ottenere ciò che cerchi. –

+0

Mi stavo lanciando tra il tuo e il 'np.where'. Sono andato con esso perché si adatta allo scopo in una singola riga di codice. Sembrava la soluzione migliore. Tutte erano buone risposte ... – orange

Problemi correlati