2012-01-18 12 views
31

ho trovato questo post: Python: finding an element in an arrayTrovare il valore più vicino e restituire l'indice di array in Python

ed è di tornare l'indice di un array attraverso corrispondenti valori.

D'altro canto, quello che sto pensando di fare è simile ma diverso. Mi piacerebbe trovare il valore più vicino per il valore target. Ad esempio sto cercando 4.2 ma so che nell'array non c'è 4.2 ma voglio restituire l'indice del valore 4.1 invece di 4.4.

Quale sarebbe il modo più veloce per farlo?

Sto pensando di farlo alla vecchia maniera come lo facevo con Matlab, che utilizza l'array A dove voglio ottenere l'indice da a meno il valore target e prendere l'assoluto di esso, quindi seleziona il min. Qualcosa di simile a questo: -

[~,idx] = min(abs(A - target)) 

Questo è il codice Matlab, ma io sono novizio in Python così sto pensando, c'è un modo veloce di farlo in Python?

Grazie mille per il vostro aiuto!

+0

http://stackoverflow.com/questions/2566412/find-nearest-value-in-numpy-array e http://stackoverflow.com/questions/6065697/python-numpy-quickly-find-the-index -in-un-array-il più vicino al valore può essere utile. – DSM

risposta

30

Questo è simile ad usare bisect_left, ma sarà consentono di passare in una serie di obiettivi

def find_closest(A, target): 
    #A must be sorted 
    idx = A.searchsorted(target) 
    idx = np.clip(idx, 1, len(A)-1) 
    left = A[idx-1] 
    right = A[idx] 
    idx -= target - left < right - target 
    return idx 

Qualche spiegazione:

in primo luogo il caso generale: idx = A.searchsorted(target) restituisce un indice per ogni target tale che target è tra A[index - 1] e A[index]. Io chiamo questi left e right quindi sappiamo che left < target <= right. target - left < right - target è True (o 1) quando l'obiettivo è più vicino a left e False (o 0) quando l'obiettivo è più vicino a right.

Ora il caso speciale: quando target è inferiore a tutti gli elementi di A, idx = 0. idx = np.clip(idx, 1, len(A)-1) sostituisce tutti i valori di idx < 1 con 1, quindi idx=1. In questo caso left = A[0], right = A[1] e sappiamo che target <= left <= right.Pertanto sappiamo che target - left <= 0 e right - target >= 0 quindi target - left < right - target è True salvo target == left == right e idx - True = 0.

V'è un altro caso speciale se target è maggiore di tutti gli elementi di A, in questo caso idx = A.searchsorted(target) e np.clip(idx, 1, len(A)-1) sostituisce len(A) con len(A) - 1 così idx=len(A) -1 e target - left < right - target finisce False ritorna così IDX len(A) -1. Ti lascerò lavorare anche se la logica da sola.

Ad esempio:

In [163]: A = np.arange(0, 20.) 

In [164]: target = np.array([-2, 100., 2., 2.4, 2.5, 2.6]) 

In [165]: find_closest(A, target) 
Out[165]: array([ 0, 19, 2, 2, 3, 3]) 
+0

Grazie mille @Bago! Sto cercando di capire i codici e sto avendo problemi con la parte 'idx - = target - left

+0

Totalmente preso! Grandi codici! Doppio pollice in alto Grazie @Bago! –

30

Il codice Numpy corrispondente è quasi lo stesso, tranne per il fatto che si utilizza numpy.argmin per trovare l'indice minimo.

idx = numpy.argmin(numpy.abs(A - target)) 
+3

'numpy.searchsorted' è anche utile (e più efficiente) se l'array di input è nell'ordine ordinato. –

+0

L'OP non l'ha specificato in modo specifico ma ho pensato di far notare che se 'A = [4.1, 4.4, 5, 4.1]' e 'target = 4.2'. Questo codice restituirà solo 'idx = 0' non' idx = [0, 3] '. L'unico modo di ricorrere al ciclo di ritorno è "A" confrontando ogni valore con il valore di 'idx = 0', per determinare se ce ne sono altri? – sgallen

+0

@sgallen: Il codice MAT di Matlab pubblicato fornisce 'idx = 1' (l'indice Matlab è basato su 1), quindi suppongo che gli altri non siano necessari. – kennytm

0
def finder(myList, target) 
    diff = '' 
    index = None 
    for i,num in enumerate(myList): 
     if abs(target - num) < diff: 
      diff = abs(target - num) 
      index = i 
    return index 

Spero che questo aiuti

EDIT:

Se vuoi un one-liner, allora si potrebbe come questo meglio:

min(L, key=lambda x: abs(target-x)) 
2

Possibile soluzione:

>>> a = [1.0, 3.2, -2.5, -3.1] 
>>> i = -1.5 
>>> diff = [(abs(i - x),idx) for (idx,x) in enumerate(a)] 
>>> diff 
[(2.5, 0), (4.7, 1), (1.0, 2), (1.6, 3)] 
>>> diff.sort() 
>>> diff 
[(1.0, 2), (1.6, 3), (2.5, 0), (4.7, 1)] 

Avrete l'indice del valore più vicino a diff [0] [1]

4

testati e temporizzati due soluzioni:

idx = np.searchsorted(sw, sCut) 

e

idx = np.argmin(np.abs(sw - sCut)) 

per il calcolo in un metodo costoso tempo. il tempo era 113s per il calcolo con la seconda soluzione e 132s per il calcolo con il primo.

5

Beh, più di 2 anni sono passati e ho trovato molto semplice implementazione da questo URL in realtà: Find nearest value in numpy array

L'implementazione è:

def getnearpos(array,value): 
    idx = (np.abs(array-value)).argmin() 
    return idx 

Evviva !!

Problemi correlati