2017-07-08 32 views
5

Chcę utworzyć tablicę numpy, która zawiera liczbę wystąpień wartości (od 1 do 3) w określonej lokalizacji. Na przykład, jeśli mam:Jedno rozwiązanie liniowe do edycji numpy tablic zliczeń? (python)

a = np.array([[1,2,3], 
       [3,2,1], 
       [2,1,3], 
       [1,1,1]]) 

Chcę wrócić tablicę tak:

[[[ 1 0 0] 
    [ 0 1 0] 
    [ 0 0 1]] 

[[ 0 0 1] 
    [ 0 1 0] 
    [ 1 0 0]] 

[[ 0 1 0] 
    [ 1 0 0] 
    [ 0 0 1]] 

[[ 1 0 0] 
    [ 1 0 0] 
    [ 1 0 0]]] 

Gdzie tablica mówi mi, że 1 występuje raz na pierwszej pozycji, 2 występuje raz w druga pozycja, 3 występuje raz w trzeciej pozycji, 1 występuje raz w czwartej pozycji, itd. Później, będę miał więcej macierzy wejściowych o tych samych wymiarach, i chciałbym dodać na sumach wartości do tej tablicy zliczeń.

Kod mam teraz jest:

a = np.array([[1,2,3], 
       [3,2,1], 
       [2,1,3], 
       [1,1,1]]) 

cumulative = np.zeros((4,3,3)) 

for r in range(len(cumulative)): 
    for c in range(len(cumulative[0])): 
     cumulative[r, c, a[r,c]-1] +=1 

To daje mi wyjście chcę. Jednak chciałbym skondensować do pętli w jednej linii, wykorzystując linię podobną do tej:

cumulative[:, :, a[:, :]-1] +=1 

Linia ta nie działa, i nie mogę znaleźć coś w Internecie, w jaki sposób wykonać tę operację. Jakieś sugestie?

Odpowiedz

3

IIUC, można skorzystać z nadawania:

In [93]: ((a[:, None] - 1) == np.arange(3)[:, None]).swapaxes(2, 1).astype(int) 
Out[93]: 
array([[[1, 0, 0], 
     [0, 1, 0], 
     [0, 0, 1]], 

     [[0, 0, 1], 
     [0, 1, 0], 
     [1, 0, 0]], 

     [[0, 1, 0], 
     [1, 0, 0], 
     [0, 0, 1]], 

     [[1, 0, 0], 
     [1, 0, 0], 
     [1, 0, 0]]]) 
+0

To cool! Czy mógłbyś wyjaśnić dokładnie, jak to działa? (przepraszam, stosunkowo nowy w python) –

1

Technicznie nie jest to jednoelement, ale jeśli zignorujesz PEP 8's maximum line length, możesz zredukować go do dwóch linii.

a = np.array([[1,2,3], 
       [3,2,1], 
       [2,1,3], 
       [1,1,1]]) 

out = np.zeros((a.shape[0], 1 + a.max() - a.min(), a.shape[1]), dtype=np.int8) 
out[np.repeat(np.arange(a.shape[0]), a.shape[1]), np.subtract(
    a, a.min())[:].flatten(), np.tile(np.arange(a.shape[1]), a.shape[0])] = 1 
print(out) 

Które wyjścia;

[[[1 0 0] 
    [0 1 0] 
    [0 0 1]] 

[[0 0 1] 
    [0 1 0] 
    [1 0 0]] 

[[0 1 0] 
    [1 0 0] 
    [0 0 1]] 

[[1 0 0] 
    [1 0 0] 
    [1 0 0]]] 

To nie jest chyba najbardziej gainly ani wdzięku rozwiązanie i niestety nie przeskalować do n wymiarach, ale mam nadzieję, że to (prawie jedna wkładka) jest wystarczająco wektoryzowane dla Ciebie.


Jest dość mocny, więc krótko omówię, jak to działa.

  • Tablica wyjściowa jest utworzona pełna zer domyślnie, o całkowitej długości jest „one-hot wektory” równy zakresowi tablicy wejściowej (I zakłada to, co chciał ponieważ nie było bez wiersza dla wartości zero podanej w twoim przykładzie).

  • np.tile i np.repeatnp.arange stosowane są do wytwarzania pierwszego i ostatniego tablic wskaźnik, to indeksy każdego elementu a.

  • Fancy indicing jest używany do wypełnienia zestaw wskaźników z szeregu pasującym do 1.

1
np.concatenate((a==1,a==2,a==3),axis=1).reshape((4,3,3)).transpose(0,2,1) + 0