6.12. Urval och omarrangering#

Reduktioner kollapsade en array ned till en skalär eller ett resultat av lägre rang. Urval täcker de operationer som väljer vilka element som överlever och var de hamnar: villkorligt val, klippning, sortering, uppslagning av index, omordning längs en axel.

6.12.1. Villkorligt val#

where() returnerar en array som tar element från x där villkoret är sant och från y annars. De tre operanderna broadcastas tillsammans:

a = np.array([1, 2, 3, 4, 5], dtype=np.float)
np.where(a < 3, a, 0.0)
# array([1.0, 2.0, 0.0, 0.0, 0.0])

Detta är rätt verktyg för ett ”if/else per element” utan att skriva en Python-loop.

clip() är en förkortning för maximum(lo, minimum(a, hi)) – mätta värdena till ett intervall:

np.clip(a, 2.0, 4.0)
# array([2.0, 2.0, 3.0, 4.0, 4.0])

maximum() och minimum() tar två operander och returnerar elementvis det större / mindre:

np.maximum(a, 3.0)
np.minimum(a, np.array([5, 4, 3, 2, 1]))

6.12.2. Hitta index#

nonzero() returnerar koordinaterna för varje element som inte är noll, uppdelade i en indexarray per dimension. För 2-D-indata är resultatet en tupel av två arrayer: den första innehåller radindexen, den andra innehåller kolumnindexen. Att para ihop dem kolumnvis ger (row, col) för varje position som inte är noll:

m = np.array([[0, 2, 0],
              [3, 0, 0]], dtype=np.float)
np.nonzero(m)
# (array([0, 1], dtype=uint16), array([1, 0], dtype=uint16))

De element i m som inte är noll är m[0, 1] = 2 och m[1, 0] = 3. Den första returnerade arrayen [0, 1] ger deras radindex; den andra [1, 0] ger deras kolumnindex. Att läsa de två arrayerna sida vid sida återskapar positionerna (0, 1) och (1, 0).

Två reduktioner producerar också index:

  • argmin() / argmax() – index för det minsta / största elementet.

  • argsort() – en heltalsarray som skulle sortera indata längs den givna axeln (standard är den sista):

    a = np.array([40, 10, 30, 20], dtype=np.uint8)
    idx = np.argsort(a)             # array([1, 3, 2, 0], dtype=uint16)
    a[idx]                          # array([10, 20, 30, 40])
    

    argsort returnerar alltid uint16; arrayen som sorteras får därför inte ha fler än 65 535 element på den sorterade axeln.

bincount() räknar förekomster av varje icke-negativt heltal i en 1-D uint8 / uint16-indata:

histogram = np.bincount(np.array([0, 1, 1, 2, 2, 2], dtype=np.uint8))
# array([1, 2, 3], dtype=uint16)

Användbart för att bygga histogram av pixelvärden med små heltal utan att skriva en Python-loop.

6.12.3. Sortering och omordning#

sort() returnerar en sorterad kopia av arrayen längs den givna axeln (den sista som standard). Använd sort() direkt på arrayen för en version på plats:

np.sort(np.array([3, 1, 2], dtype=np.float))
# array([1.0, 2.0, 3.0])

flip() vänder ordningen längs den givna axeln (varje axel när ingen axis anges):

np.flip(np.array([1, 2, 3, 4]))
# array([4, 3, 2, 1])

roll() förskjuter element cykliskt med det givna antalet. Användbart för att implementera ett skiftregister i ringbuffert-stil:

np.roll(np.array([1, 2, 3, 4]), 1)
# array([4, 1, 2, 3])

take() är den explicita formen av avancerad indexering – plocka element vid godtyckliga index:

a = np.array([10, 20, 30, 40, 50], dtype=np.uint8)
np.take(a, [0, 2, 4])
# array([10, 30, 50], dtype=uint8)

6.12.4. Filtrering och strukturella ändringar#

compress() är den explicita formen av boolesk indexering – returnera de delar av a som väljs av det booleska villkoret:

a = np.array([10, 20, 30, 40], dtype=np.uint8)
np.compress(a > 15, a)
# array([20, 30, 40], dtype=uint8)

delete() returnerar en kopia där posterna vid de givna indexen är borttagna:

a = np.array([10, 20, 30, 40, 50], dtype=np.uint8)
np.delete(a, [1, 3])
# array([10, 30, 50], dtype=uint8)

diff() returnerar den n:te diskreta framåtdifferensen av arrayen längs en axel. Används för att beräkna förstaordningsändringar mellan intilliggande sampel:

samples = np.array([1, 3, 6, 10, 15], dtype=np.float)
np.diff(samples)
# array([2.0, 3.0, 4.0, 5.0])

6.12.5. Vad varje operation kostar#

Nästan varje funktion på denna sida returnerar en nyallokerad array. Två undantag:

  • sort() sorterar på plats; den fristående funktionen sort() returnerar en sorterad kopia.

  • take() accepterar nyckelordet out= för att skriva in i en buffert som redan finns.

I en loop som körs många gånger per sekund, föredra sort() på plats och återanvänd förallokerade buffertar överallt annars. Booleska masker allokeras själva varje gång jämförelsen körs – bygg en mask en gång och återanvänd den över flera operationer i stället för att bygga om den inuti varje iteration.