Is er een NumPy-functie om de eerste index van iets in een array te retourneren?

Ik weet dat er een methode is voor een Python-lijst om de eerste index van iets te retourneren:

>>> l = [1, 2, 3]
>>> l.index(2)
1

Is er zoiets voor NumPy-arrays?


Antwoord 1, autoriteit 100%

Ja, gegeven een array, array, en een waarde, itemom naar te zoeken, kun je np.whereals:

itemindex = numpy.where(array==item)

Het resultaat is een tuple met eerst alle rij-indices en daarna alle kolomindices.

Als een array bijvoorbeeld twee dimensies heeft en uw item op twee locaties bevatte, dan

array[itemindex[0][0]][itemindex[1][0]]

zou gelijk zijn aan uw artikel en dat geldt ook voor:

array[itemindex[0][1]][itemindex[1][1]]

Antwoord 2, autoriteit 14%

Als u de index van het eerste voorkomen van slechts één waardenodig heeft, kunt u nonzero(of wheregebruiken, wat neerkomt op de hetzelfde in dit geval):

>>> t = array([1, 1, 1, 2, 2, 3, 8, 3, 8, 8])
>>> nonzero(t == 8)
(array([6, 8, 9]),)
>>> nonzero(t == 8)[0][0]
6

Als je de eerste index van elk van vele waardennodig hebt, kun je natuurlijk hetzelfde herhalen als hierboven, maar er is een truc die sneller kan zijn. Het volgende vindt de indices van het eerste element van elke subreeks:

>>> nonzero(r_[1, diff(t)[:-1]])
(array([0, 3, 5, 6, 7, 8]),)

Merk op dat het het begin van zowel de deelreeksen van 3s als beide deelreeksen van 8s vindt:

[1, 1, 1, 2, 2, 3, 8, 3 , 8, 8]

Het is dus iets anders dan het vinden van het eerste voorkomenvan elke waarde. In je programma kun je misschien werken met een gesorteerde versie van tom te krijgen wat je wilt:

>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)

Antwoord 3, autoriteit 10%

Je kunt een NumPy-array ook converteren naar een lijst in de lucht en de index ophalen. Bijvoorbeeld,

l = [1,2,3,4,5] # Python list
a = numpy.array(l) # NumPy array
i = a.tolist().index(2) # i will return index of 2
print i

Er wordt 1 afgedrukt


Antwoord 4, autoriteit 4%

Om een ​​zeer performante en handige alternatief gebaseerd op np.ndenumerateom de eerste index te vinden:

from numba import njit
import numpy as np
@njit
def index(array, item):
    for idx, val in np.ndenumerate(array):
        if val == item:
            return idx
    # If no item was found return None, other return types might be a problem due to
    # numbas type inference.

Dit is vrij snel en gaat op natuurlijke wijze om met multidimensionale arrays:

>>> arr1 = np.ones((100, 100, 100))
>>> arr1[2, 2, 2] = 2
>>> index(arr1, 2)
(2, 2, 2)
>>> arr2 = np.ones(20)
>>> arr2[5] = 2
>>> index(arr2, 2)
(5,)

Dit kan veel snellerzijn (omdat het de bewerking kortsluit) dan elke benadering die np.whereof np.nonzerogebruikt.


Echter np.argwherekan ook gracieusomgaan met multidimensionale arrays (je zou het handmatig naar een tuple moeten casten enhet is niet kortgesloten) maar het zou mislukken als er geen overeenkomst is gevonden:

>>> tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> tuple(np.argwhere(arr2 == 2)[0])
(5,)

Antwoord 5, autoriteit 2%

l.index(x)retourneert de kleinste izodanig dat ide index is van de eerste keer dat x in de lijst voorkomt.

Men kan er gerust van uitgaan dat de functie index()in Python zo is geïmplementeerd dat deze stopt na het vinden van de eerste overeenkomst, en dit resulteert in een optimale gemiddelde prestatie.

Voor het vinden van een element dat stopt na de eerste overeenkomst in een NumPy-array, gebruikt u een iterator (ndenumerate).

In [67]: l=range(100)
In [68]: l.index(2)
Out[68]: 2

NumPy-array:

In [69]: a = np.arange(100)
In [70]: next((idx for idx, val in np.ndenumerate(a) if val==2))
Out[70]: (2L,)

Merk op dat beide methoden index()en nexteen fout retourneren als het element niet wordt gevonden. Met nextkan men een tweede argument gebruiken om een ​​speciale waarde terug te geven in het geval dat het element niet gevonden wordt, bijvoorbeeld

In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None)

Er zijn andere functies in NumPy (argmax, whereen nonzero) die kunnen worden gebruikt om een ​​element in een array te vinden, maar ze hebben allemaal het nadeel dat ze door de hele array gaan op zoek naar allevoorkomens, en dus niet geoptimaliseerd zijn voor het vinden van het eerste element. Merk ook op dat whereen nonzeroarrays retourneren, dus je moet het eerste element selecteren om de index te krijgen.

In [71]: np.argmax(a==2)
Out[71]: 2
In [72]: np.where(a==2)
Out[72]: (array([2], dtype=int64),)
In [73]: np.nonzero(a==2)
Out[73]: (array([2], dtype=int64),)

Tijdvergelijking

Even kijken of voor grote arrays de oplossing met een iterator sneller is wanneer het gezochte item aan het begin van de array staat(met behulp van %timeitin de IPython-shell) :

In [285]: a = np.arange(100000)
In [286]: %timeit next((idx for idx, val in np.ndenumerate(a) if val==0))
100000 loops, best of 3: 17.6 µs per loop
In [287]: %timeit np.argmax(a==0)
1000 loops, best of 3: 254 µs per loop
In [288]: %timeit np.where(a==0)[0][0]
1000 loops, best of 3: 314 µs per loop

Dit is een open NumPy GitHub-probleem.

Zie ook: Numpy: vind snel de eerste index van waarde


Antwoord 6, autoriteit 2%

Als je dit als index naar iets anders gaat gebruiken, kun je booleaanse indices gebruiken als de arrays broadcastable zijn; je hebt geen expliciete indexen nodig. De absoluut eenvoudigste manier om dit te doen, is door simpelweg te indexeren op basis van een waarheidswaarde.

other_array[first_array == item]

Elke booleaanse bewerking werkt:

a = numpy.arange(100)
other_array[first_array > 50]

De methode die niet nul is, heeft ook booleans nodig:

index = numpy.nonzero(first_array == item)[0][0]

De twee nullen zijn voor de tupel van indices (ervan uitgaande dat first_array 1D is) en dan het eerste item in de reeks indices.


Antwoord 7, autoriteit 2%

Voor eendimensionale gesorteerdearrays zou het veel eenvoudiger en efficiënter zijn om O(log(n)) te gebruiken numpy.searchsortedwat een NumPy geheel getal (positie) retourneert. Bijvoorbeeld,

arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)

Zorg er wel voor dat de array al is gesorteerd

Controleer ook of de geretourneerde index i daadwerkelijk het gezochte element bevat, aangezien het belangrijkste doel van searchsorted is om indices te vinden waar elementen moeten worden ingevoegd om de volgorde te behouden.

if arr[i] == 3:
    print("present")
else:
    print("not present")

Antwoord 8

Als u op elk criterium wilt indexeren, kunt u zoiets als het volgende doen:

In [1]: from numpy import *
In [2]: x = arange(125).reshape((5,5,5))
In [3]: y = indices(x.shape)
In [4]: locs = y[:,x >= 120] # put whatever you want in place of x >= 120
In [5]: pts = hsplit(locs, len(locs[0]))
In [6]: for pt in pts:
   .....:         print(', '.join(str(p[0]) for p in pt))
4, 4, 0
4, 4, 1
4, 4, 2
4, 4, 3
4, 4, 4

En hier is een snelle functie om te doen wat list.index() doet, behalve dat er geen uitzondering wordt gegenereerd als deze niet wordt gevonden. Pas op — dit is waarschijnlijk erg traag op grote arrays. Je kunt dit waarschijnlijk patchen op arrays als je het liever als methode gebruikt.

def ndindex(ndarray, item):
    if len(ndarray.shape) == 1:
        try:
            return [ndarray.tolist().index(item)]
        except:
            pass
    else:
        for i, subarray in enumerate(ndarray):
            try:
                return [i] + ndindex(subarray, item)
            except:
                pass
In [1]: ndindex(x, 103)
Out[1]: [4, 0, 3]

Antwoord 9

Voor 1D-arrays raad ik np.flatnonzero(array == value)[0]aan, wat gelijk is aan beide np.nonzero(array == value)[0][0]en np.where(array == value)[0][0]maar vermijdt de lelijkheid van het unboxen van een 1-element tuple.


Antwoord 10

Een alternatief voor het selecteren van het eerste element van np.where() is om een ​​generator-expressie samen met enumerate te gebruiken, zoals:

>>> import numpy as np
>>> x = np.arange(100)   # x = array([0, 1, 2, 3, ... 99])
>>> next(i for i, x_i in enumerate(x) if x_i == 2)
2

Voor een tweedimensionale array zou men doen:

>>> x = np.arange(100).reshape(10,10)   # x = array([[0, 1, 2,... 9], [10,..19],])
>>> next((i,j) for i, x_i in enumerate(x) 
...            for j, x_ij in enumerate(x_i) if x_ij == 2)
(0, 2)

Het voordeel van deze aanpak is dat het stopt met het controleren van de elementen van de array nadat de eerste overeenkomst is gevonden, terwijl np.where alle elementen op een overeenkomst controleert. Een generator-expressie zou sneller zijn als er vroeg in de array een overeenkomst is.


Antwoord 11

Er zijn veel bewerkingen in NumPy die misschien kunnen worden samengevoegd om dit te bereiken. Dit retourneert indexen van elementen die gelijk zijn aan item:

numpy.nonzero(array - item)

Je zou dan de eerste elementen van de lijsten kunnen nemen om een ​​enkel element te krijgen.


Antwoord 12

Het numpy_indexedpakket (disclaimer, ik ben de auteur) bevat een gevectoriseerd equivalent van list.index voor numpy.ndarray; dat is:

sequence_of_arrays = [[0, 1], [1, 2], [-5, 0]]
arrays_to_query = [[-5, 0], [1, 0]]
import numpy_indexed as npi
idx = npi.indices(sequence_of_arrays, arrays_to_query, missing=-1)
print(idx)   # [2, -1]

Deze oplossing heeft gevectoriseerde prestaties, generaliseert naar ndarrays en heeft verschillende manieren om met ontbrekende waarden om te gaan.


Antwoord 13

Gebruik ndindex

Voorbeeldarray

arr = np.array([[1,4],
                 [2,3]])
print(arr)
...[[1,4],
    [2,3]]

maak een lege lijst om de index en de element-tupels op te slaan

index_elements = []
 for i in np.ndindex(arr.shape):
     index_elements.append((arr[i],i))

converteer de lijst met tuples naar een woordenboek

index_elements = dict(index_elements)

De sleutels zijn de elementen en de waarden zijn hun
indexen – gebruik de toetsen om toegang te krijgen tot de index

index_elements[4] 

uitvoer

 ... (0,1)

Antwoord 14

Een andere oplossing gevonden met loops:

new_array_of_indicies = []
for i in range(len(some_array)):
  if some_array[i] == some_value:
    new_array_of_indicies.append(i)

Antwoord 15

Er is een vrij idiomatische en gevectoriseerde manier om dit in numpy te doen. Het gebruikt een eigenaardigheid van de functie np.argmax() om dit te bereiken — als veel waarden overeenkomen, retourneert het de index van de eerste overeenkomst. De truc is dat er voor booleans altijd maar twee waarden zijn: True (1) en False (0). Daarom is de geretourneerde index die van de eerste True.

Voor het eenvoudige voorbeeld kunt u zien dat het werkt met het volgende

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

Een goed voorbeeld is het berekenen van buckets, b.v. voor het categoriseren. Laten we zeggen dat je een array van snijpunten hebt en je wilt de “bucket” die overeenkomt met elk element van je array. Het algoritme berekent de eerste index van cutswaarbij x < cuts(na het opvullen van cutsmet np.Infitnity). Ik zou broadcasting kunnen gebruiken om de vergelijkingen uit te zenden en vervolgens argmax toepassen langs de cuts-uitgezonden as.

>>> cuts = np.array([10, 50, 100])
>>> cuts_pad = np.array([*cuts, np.Infinity])
>>> x   = np.array([7, 11, 80, 443])
>>> bins = np.argmax( x[:, np.newaxis] < cuts_pad[np.newaxis, :], axis = 1)
>>> print(bins)
[0, 1, 2, 3]

Zoals verwacht valt elke waarde van xin een van de opeenvolgende bakken, met goed gedefinieerd en gemakkelijk te specificeren randgevalgedrag.


Antwoord 16

Een andere optie die niet eerder is genoemd, is de bisect-module, die ook op lijsten werkt, maar een voorgesorteerde lijst/array vereist:

import bisect
import numpy as np
z = np.array([104,113,120,122,126,138])
bisect.bisect_left(z, 122)

opbrengst

3

bisect geeft ook een resultaat als het getal dat je zoekt niet in de array voorkomt, zodat het getal op de juiste plaats kan worden ingevoegd.


Antwoord 17

Opmerking: dit is voor python 2.7-versie

Je kunt een lambda-functie gebruiken om het probleem op te lossen, en het werkt zowel op de NumPy-array als op de lijst.

your_list = [11, 22, 23, 44, 55]
result = filter(lambda x:your_list[x]>30, range(len(your_list)))
#result: [3, 4]
import numpy as np
your_numpy_array = np.array([11, 22, 23, 44, 55])
result = filter(lambda x:your_numpy_array [x]>30, range(len(your_list)))
#result: [3, 4]

En je kunt gebruiken

result[0]

om de eerste index van de gefilterde elementen te krijgen.

Gebruik voor python 3.6

list(result)

in plaats van

result

LEAVE A REPLY

Please enter your comment!
Please enter your name here

three + 17 =

Other episodes