2015-03-14 19 views
5

Chcę wybrać określone elementy tablicy i wykonać obliczenia średniej ważonej na podstawie wartości. Jednak użycie warunku filtru niszczy oryginalną strukturę tablicy. arr, który był w kształcie (2, 2, 3, 2) został przekształcony w tablicę jednowymiarową. Nie przyda mi się to, ponieważ nie wszystkie te elementy muszą być ze sobą połączone później (ale pod nimi). Jak mogę uniknąć tego spłaszczenia?Utrata rozmiaru tablicy Numpy przy maskowaniu

>>> 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

Opracowanie na obliczeniach, które trzeba zrobić z tymi wartościami. W jaki sposób wykorzystasz strukturę 'arr'? – hpaulj

Odpowiedz

5

Zamówienie numpy.where

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

Aby zachować tę samą wymiarowości idziesz potrzebować wartość wypełnienia. W poniższym przykładzie używam 0, ale można też użyć np.nan

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

powraca

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

Tego właśnie szukałem. – orange

3

Spójrz na 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] wybiera te elementy, gdzie maska ​​jest True. Jaki rodzaj struktury lub kształtu ma ta selekcja? Płaskie to jedyna rzecz, która ma sens, prawda? arr sam się nie zmienia.

Można wyzerować warunki, które nie pasują do maski,

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]]]]) 

Teraz można zrobić sumy masy lub średnie nad różnymi wymiarami.

np.nonzero (lub np.where) może również być użyteczny, co daje indeksy w wybranych kategoriach:

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

można rozważyć przy użyciu np.ma.masked_array do reprezentowania podzbioru elementów, które spełniają swój warunek:

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]]]] 

Jak widać, zamaskowana tablica zachowuje swoje oryginalne wymiary. Możesz uzyskać dostęp do podstawowych danych i maski za pomocą odpowiednio atrybutów .data i .mask. Większość funkcji NumPy nie weźmie pod uwagę maskowanych wartości, np:

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

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

Wynikiem operacji element mądry na zamaskowanego tablicy i non-zamaskowanego tablicy będzie również zachować wartości maski:

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]]]] 

suma jest obliczana tylko na niemaskowanej wartości masked_arr - widać to patrząc na 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

Interesujące. Myślałem, że 'arr [arr <3]' niejawnie utworzy maskowaną tablicę - nauczy się czegoś nowego (+1). – orange

+1

Pamiętaj, że 'arr <3' jest po prostu tablicą boolowską, a indeksowanie z tablicą boolowską zawsze spowoduje zwrócenie tych elementów w' arr', gdzie indeks boolowski to 'True'. Z ciekawości, dlaczego zdecydowałeś się pójść z 'np.where' na końcu? Z tych trzech odpowiedzi wydaje się, że to najmniej bezpośredni sposób na osiągnięcie tego, o co prosisz. –

+0

Przerzucałem między twoją a 'np.where'. Poszedłem z tym, ponieważ pasuje do celu w jednym wierszu kodu. Wydawało się, że najlepiej pasuje. Wszystkie były dobrymi odpowiedziami ... – orange