2015-08-17 15 views
7

mam numpy tablicę, która posiada wektorów 4-wymiarowe, które posiadają następujący format (X, Y, Z, W)Filtrowanie numpy mikromacierzy opartych na największej wartości

rozmiar tablicy jest 4 x N. Teraz dane, które posiadam, znajdują się w miejscach, w których mam (x, y, z) lokalizacje przestrzenne, a w ma pewien szczególny pomiar w tej lokalizacji. Teraz może być wiele pomiarów związanych z pozycją (x, y, z) (mierzoną jako pływaki).

Co chcę zrobić, to odfiltrować tablicę, aby uzyskać nową tablicę, w której otrzymam maksymalny pomiar odpowiadający każdej z pozycji (x, y, z).

Więc jeśli moje dane jak:

x, y, z, w1 
x, y, z, w2 
x, y, z, w3 

gdzie W1 jest większa niż W2 i W3, przefiltrowane dane byłoby:

x, y, z, w1 

Więc bardziej konkretnie, że mam dane, takie jak:

[[ 0.7732126 0.48649481 0.29771819 0.91622924] 
[ 0.7732126 0.48649481 0.29771819 1.91622924] 
[ 0.58294263 0.32025559 0.6925856 0.0524125 ] 
[ 0.58294263 0.32025559 0.6925856 0.05 ] 
[ 0.58294263 0.32025559 0.6925856 1.7 ] 
[ 0.3239913 0.7786444 0.41692853 0.10467392] 
[ 0.12080023 0.74853649 0.15356663 0.4505753 ] 
[ 0.13536096 0.60319054 0.82018125 0.10445047] 
[ 0.1877724 0.96060999 0.39697999 0.59078612]] 

ten powinien powrócić

[[ 0.7732126 0.48649481 0.29771819 1.91622924] 
[ 0.58294263 0.32025559 0.6925856 1.7 ] 
[ 0.3239913 0.7786444 0.41692853 0.10467392] 
[ 0.12080023 0.74853649 0.15356663 0.4505753 ] 
[ 0.13536096 0.60319054 0.82018125 0.10445047] 
[ 0.1877724 0.96060999 0.39697999 0.59078612]] 
+0

będzie wpisy dla tego samego (x, y, z) położeniu zawsze kolejne, jak w przykładowych danych czy będą rozproszone? O ile wpisów będziesz miał w praktyce? – jme

+0

Mogą być niestety rozproszone. Nigdy nie będą więcej niż 4. Wydajność nie jest na to krytyczna. – Luca

+5

FYI: Jest to operacja "grupa po sobie" (patrz http://pandas.pydata.org/pandas-docs/stable/groupby.html). Grupujesz według pierwszych trzech kolumn, a następnie stosujesz maksymalną funkcję do grup. Jest to całkiem łatwe do zrobienia z biblioteką taką jak pandy (http://pandas.pydata.org/). –

Odpowiedz

3

to zawiłe, ale prawdopodobnie jest tak dobra, jak masz zamiar dostać tylko za pomocą numpy ...

Po pierwsze, używamy lexsort, aby wstawić wszystkie wpisy o tych samych współrzędnych. Z a jest macierz próbki:

>>> perm = np.lexsort(a[:, 3::-1].T) 
>>> a[perm] 
array([[ 0.12080023, 0.74853649, 0.15356663, 0.4505753 ], 
     [ 0.7732126 , 0.48649481, 0.29771819, 0.91622924], 
     [ 0.7732126 , 0.48649481, 0.29771819, 1.91622924], 
     [ 0.1877724 , 0.96060999, 0.39697999, 0.59078612], 
     [ 0.3239913 , 0.7786444 , 0.41692853, 0.10467392], 
     [ 0.58294263, 0.32025559, 0.6925856 , 0.0524125 ], 
     [ 0.58294263, 0.32025559, 0.6925856 , 0.05  ], 
     [ 0.58294263, 0.32025559, 0.6925856 , 1.7  ], 
     [ 0.13536096, 0.60319054, 0.82018125, 0.10445047]]) 

Należy zauważyć, że przez odwrócenie osi jesteśmy sortując x, łamiąc związki z y, następnie z, następnie w.

Ponieważ jest to maksymalna szukamy, po prostu trzeba wziąć ostatni wpis w każdej grupie, która jest całkiem prosta rzecz do zrobienia:

>>> a_sorted = a[perm] 
>>> last = np.concatenate((np.all(a_sorted[:-1, :3] != a_sorted[1:, :3], axis=1), 
          [True])) 
>>> a_unique_max = a_sorted[last] 
>>> a_unique_max 
array([[ 0.12080023, 0.74853649, 0.15356663, 0.4505753 ], 
     [ 0.13536096, 0.60319054, 0.82018125, 0.10445047], 
     [ 0.1877724 , 0.96060999, 0.39697999, 0.59078612], 
     [ 0.3239913 , 0.7786444 , 0.41692853, 0.10467392], 
     [ 0.58294263, 0.32025559, 0.6925856 , 1.7  ], 
     [ 0.7732126 , 0.48649481, 0.29771819, 1.91622924]]) 

Jeśli raczej nie będzie miał wyjścia sortowane, ale zachować je w oryginalnej kolejności Wpadli w oryginalnej tablicy, można również uzyskać, że przy pomocy perm:

>>> a_unique_max[np.argsort(perm[last])] 
array([[ 0.7732126 , 0.48649481, 0.29771819, 1.91622924], 
     [ 0.58294263, 0.32025559, 0.6925856 , 1.7  ], 
     [ 0.3239913 , 0.7786444 , 0.41692853, 0.10467392], 
     [ 0.12080023, 0.74853649, 0.15356663, 0.4505753 ], 
     [ 0.13536096, 0.60319054, 0.82018125, 0.10445047], 
     [ 0.1877724 , 0.96060999, 0.39697999, 0.59078612]]) 

to będzie działać tylko do maksimum, a przychodzi jako uboczny produkt sortowania. Jeśli jesteś po innej funkcji, powiedzmy iloczyn wszystkich same współrzędne pozycji, można zrobić coś takiego:

>>> first = np.concatenate(([True], 
          np.all(a_sorted[:-1, :3] != a_sorted[1:, :3], axis=1))) 
>>> a_unique_prods = np.multiply.reduceat(a_sorted, np.nonzero(first)[0]) 

i trzeba będzie grać trochę wokół z tych wyników zainstalować tablicę powrotną.

-1

Można użyć indeksowania logicznego.

użyję losowe dane na przykład:

>>> myarr = np.random.random((6, 4)) 
>>> print(myarr) 
[[ 0.7732126 0.48649481 0.29771819 0.91622924] 
[ 0.58294263 0.32025559 0.6925856 0.0524125 ] 
[ 0.3239913 0.7786444 0.41692853 0.10467392] 
[ 0.12080023 0.74853649 0.15356663 0.4505753 ] 
[ 0.13536096 0.60319054 0.82018125 0.10445047] 
[ 0.1877724 0.96060999 0.39697999 0.59078612]] 

Aby uzyskać wiersz lub wiersze, gdzie ostatnia kolumna jest największa, to zrobić:

>>> greatest = myarr[myarr[:, 3]==myarr[:, 3].max()] 
>>> print(greatest) 
[[ 0.7732126 0.48649481 0.29771819 0.91622924]] 

Co to robi to robi ostatnia kolumna z myarr i znajduje maksimum tej kolumny, znajduje wszystkie elementy tej kolumny równe maksimum, a następnie pobiera odpowiednie wiersze.

+0

To nie jest zachowanie, którego szukam. Dokonałem edycji tego pytania, aby miejmy nadzieję uczynić go bardziej zrozumiałym. – Luca

-1

Można użyć np.argmax

x[np.argmax(x[:,3]),:]

>>> x = np.random.random((5,4)) 
>>> x 
array([[ 0.25461146, 0.35671081, 0.54856798, 0.2027313 ], 
     [ 0.17079029, 0.66970362, 0.06533572, 0.31704254], 
     [ 0.4577928 , 0.69022073, 0.57128696, 0.93995176], 
     [ 0.29708841, 0.96324181, 0.78859008, 0.25433235], 
     [ 0.58739451, 0.17961551, 0.67993786, 0.73725493]]) 
>>> x[np.argmax(x[:,3]),:] 
array([ 0.4577928 , 0.69022073, 0.57128696, 0.93995176]) 
+0

To nie jest zachowanie, którego szukam. Dokonałem edycji tego pytania, aby miejmy nadzieję uczynić go bardziej zrozumiałym. – Luca

2

Widzę, że masz już wskaźnik w stronę pand w komentarzach. FWIW, oto jak uzyskać pożądane zachowanie, zakładając, że nie dbasz o ostateczną kolejność sortowania, ponieważ groupby to zmienia.

In [14]: arr 
Out[14]: 
array([[ 0.7732126 , 0.48649481, 0.29771819, 0.91622924], 
     [ 0.7732126 , 0.48649481, 0.29771819, 1.91622924], 
     [ 0.58294263, 0.32025559, 0.6925856 , 0.0524125 ], 
     [ 0.58294263, 0.32025559, 0.6925856 , 0.05  ], 
     [ 0.58294263, 0.32025559, 0.6925856 , 1.7  ], 
     [ 0.3239913 , 0.7786444 , 0.41692853, 0.10467392], 
     [ 0.12080023, 0.74853649, 0.15356663, 0.4505753 ], 
     [ 0.13536096, 0.60319054, 0.82018125, 0.10445047], 
     [ 0.1877724 , 0.96060999, 0.39697999, 0.59078612]]) 

In [15]: import pandas as pd 

In [16]: pd.DataFrame(arr) 
Out[16]: 
      0   1   2   3 
0 0.773213 0.486495 0.297718 0.916229 
1 0.773213 0.486495 0.297718 1.916229 
2 0.582943 0.320256 0.692586 0.052413 
3 0.582943 0.320256 0.692586 0.050000 
4 0.582943 0.320256 0.692586 1.700000 
5 0.323991 0.778644 0.416929 0.104674 
6 0.120800 0.748536 0.153567 0.450575 
7 0.135361 0.603191 0.820181 0.104450 
8 0.187772 0.960610 0.396980 0.590786 

In [17]: pd.DataFrame(arr).groupby([0,1,2]).max().reset_index() 
Out[17]: 
      0   1   2   3 
0 0.120800 0.748536 0.153567 0.450575 
1 0.135361 0.603191 0.820181 0.104450 
2 0.187772 0.960610 0.396980 0.590786 
3 0.323991 0.778644 0.416929 0.104674 
4 0.582943 0.320256 0.692586 1.700000 
5 0.773213 0.486495 0.297718 1.916229 
+0

Dzięki. Bardzo dobre rozwiązanie również. Mam zamiar również szczegółowo to zbadać. – Luca

2

Można zacząć od lex-sorting wejściowej tablicy przynieść wpisy z pierwszych trzech identycznych elementów z rzędu. Następnie utwórz kolejną tablicę 2D do przechowywania ostatnich wpisów w kolumnie, tak aby elementy odpowiadające każdemu zduplikowanemu tripletowi trafiały do ​​tych samych wierszy. Następnie znajdź max wzdłuż axis=1 dla tej tablicy 2D, a tym samym uzyskaj ostateczne wyjście max dla każdego takiego unikatowego tripletu. Oto realizacja, zakładając A jako tablicy wejściowej -

# Lex sort A 
sortedA = A[np.lexsort(A[:,:-1].T)] 

# Mask of start of unique first three columns from A 
start_unqA = np.append(True,~np.all(np.diff(sortedA[:,:-1],axis=0)==0,axis=1)) 

# Counts of unique first three columns from A 
counts = np.bincount(start_unqA.cumsum()-1) 
mask = np.arange(counts.max()) < counts[:,None] 

# Group A's last column into rows based on uniqueness from first three columns 
grpA = np.empty(mask.shape) 
grpA.fill(np.nan) 
grpA[mask] = sortedA[:,-1] 

# Concatenate unique first three columns from A and 
# corresponding max values for each such unique triplet 
out = np.column_stack((sortedA[start_unqA,:-1],np.nanmax(grpA,axis=1))) 

run Sample -

In [75]: A 
Out[75]: 
array([[ 1, 1, 1, 96], 
     [ 1, 2, 2, 48], 
     [ 2, 1, 2, 33], 
     [ 1, 1, 1, 24], 
     [ 1, 1, 1, 94], 
     [ 2, 2, 2, 5], 
     [ 2, 1, 1, 17], 
     [ 2, 2, 2, 62]]) 

In [76]: sortedA 
Out[76]: 
array([[ 1, 1, 1, 96], 
     [ 1, 1, 1, 24], 
     [ 1, 1, 1, 94], 
     [ 2, 1, 1, 17], 
     [ 2, 1, 2, 33], 
     [ 1, 2, 2, 48], 
     [ 2, 2, 2, 5], 
     [ 2, 2, 2, 62]]) 

In [77]: out 
Out[77]: 
array([[ 1., 1., 1., 96.], 
     [ 2., 1., 1., 17.], 
     [ 2., 1., 2., 33.], 
     [ 1., 2., 2., 48.], 
     [ 2., 2., 2., 62.]]) 
Powiązane problemy