una sumar que matriz matrices elementos elemento ejemplos buscar arreglos array python search numpy

python - sumar - que es numpy



Encuentra el valor más cercano en la matriz numpy (14)

Aquí hay una extensión para encontrar el vector más cercano en una matriz de vectores.

import numpy as np def find_nearest_vector(array, value): idx = np.array([np.linalg.norm(x+y) for (x,y) in array-value]).argmin() return array[idx] A = np.random.random((10,2))*100 """ A = array([[ 34.19762933, 43.14534123], [ 48.79558706, 47.79243283], [ 38.42774411, 84.87155478], [ 63.64371943, 50.7722317 ], [ 73.56362857, 27.87895698], [ 96.67790593, 77.76150486], [ 68.86202147, 21.38735169], [ 5.21796467, 59.17051276], [ 82.92389467, 99.90387851], [ 6.76626539, 30.50661753]])""" pt = [6, 30] print find_nearest_vector(A,pt) # array([ 6.76626539, 30.50661753])

¿Existe una forma numpy-tónica, por ejemplo, la función, para encontrar el valor más cercano en una matriz?

Ejemplo:

np.find_nearest( array, value )


Aquí hay una versión con scipy para @Ari Onasafari, responde " para encontrar el vector más cercano en una variedad de vectores "

In [1]: from scipy import spatial In [2]: import numpy as np In [3]: A = np.random.random((10,2))*100 In [4]: A Out[4]: array([[ 68.83402637, 38.07632221], [ 76.84704074, 24.9395109 ], [ 16.26715795, 98.52763827], [ 70.99411985, 67.31740151], [ 71.72452181, 24.13516764], [ 17.22707611, 20.65425362], [ 43.85122458, 21.50624882], [ 76.71987125, 44.95031274], [ 63.77341073, 78.87417774], [ 8.45828909, 30.18426696]]) In [5]: pt = [6, 30] # <-- the point to find In [6]: A[spatial.KDTree(A).query(pt)[1]] # <-- the nearest point Out[6]: array([ 8.45828909, 30.18426696]) #how it works! In [7]: distance,index = spatial.KDTree(A).query(pt) In [8]: distance # <-- The distances to the nearest neighbors Out[8]: 2.4651855048258393 In [9]: index # <-- The locations of the neighbors Out[9]: 9 #then In [10]: A[index] Out[10]: array([ 8.45828909, 30.18426696])


Aquí hay una versión que manejará una matriz de "valores" no escalar:

import numpy as np def find_nearest(array, values): indices = np.abs(np.subtract.outer(array, values)).argmin(0) return array[indices]

O una versión que devuelve un tipo numérico (por ejemplo, int, float) si la entrada es escalar:

def find_nearest(array, values): values = np.atleast_1d(values) indices = np.abs(np.subtract.outer(array, values)).argmin(0) out = array[indices] return out if len(out) > 1 else out[0]


Aquí hay una versión vectorizada rápida de la solución de @Dimitri si tiene muchos values que buscar (los values pueden ser una matriz multidimensional):

#`values` should be sorted def get_closest(array, values): #make sure array is a numpy array array = np.array(array) # get insert positions idxs = np.searchsorted(array, values, side="left") # find indexes where previous index is closer prev_idx_is_less = ((idxs == len(array))|(np.fabs(values - array[np.maximum(idxs-1, 0)]) < np.fabs(values - array[np.minimum(idxs, len(array)-1)]))) idxs[prev_idx_is_less] -= 1 return array[idxs]

Puntos de referencia

> 100 veces más rápido que usar un bucle for con la solución de @ Demitri

>>> %timeit ar=get_closest(np.linspace(1, 1000, 100), np.random.randint(0, 1050, (1000, 1000))) 139 ms ± 4.04 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) >>> %timeit ar=[find_nearest(np.linspace(1, 1000, 100), value) for value in np.random.randint(0, 1050, 1000*1000)] took 21.4 seconds


Con una ligera modificación, la respuesta anterior funciona con matrices de dimensión arbitraria (1d, 2d, 3d, ...):

def find_nearest(a, a0): "Element in nd array `a` closest to the scalar value `a0`" idx = np.abs(a - a0).argmin() return a.flat[idx]

O, escrito como una sola línea:

a.flat[np.abs(a - a0).argmin()]


Creo que la forma más pitónica sería:

num = 65 # Input number array = n.random.random((10))*100 # Given array nearest_idx = n.where(abs(array-num)==abs(array-num).min())[0] # If you want the index of the element of array (array) nearest to the the given number (num) nearest_val = array[abs(array-num)==abs(array-num).min()] # If you directly want the element of array (array) nearest to the given number (num)

Este es el código básico. Puedes usarlo como una función si quieres.


Esta es una versión vectorizada de la respuesta de unutbu :

def find_nearest(array, values): array = np.asarray(array) # the last dim must be 1 to broadcast in (array - values) below. values = np.expand_dims(values, axis=-1) indices = np.abs(array - values).argmin(axis=-1) return array[indices] image = plt.imread(''example_3_band_image.jpg'') print(image.shape) # should be (nrows, ncols, 3) quantiles = np.linspace(0, 255, num=2 ** 2, dtype=np.uint8) quantiled_image = find_nearest(quantiles, image) print(quantiled_image.shape) # should be (nrows, ncols, 3)


Para matrices grandes, la (excelente) respuesta dada por @Demitri es mucho más rápida que la respuesta marcada actualmente como la mejor. He adaptado su algoritmo exacto de las siguientes dos maneras:

  1. La siguiente función funciona independientemente de si la matriz de entrada está ordenada o no.

  2. La siguiente función devuelve el índice de la matriz de entrada correspondiente al valor más cercano, que es algo más general.

Tenga en cuenta que la siguiente función también maneja un caso de borde específico que podría provocar un error en la función original escrita por @Demitri. De lo contrario, mi algoritmo es idéntico al suyo.

def find_idx_nearest_val(array, value): idx_sorted = np.argsort(array) sorted_array = np.array(array[idx_sorted]) idx = np.searchsorted(sorted_array, value, side="left") if idx >= len(array): idx_nearest = idx_sorted[len(array)-1] elif idx == 0: idx_nearest = idx_sorted[0] else: if abs(value - sorted_array[idx-1]) < abs(value - sorted_array[idx]): idx_nearest = idx_sorted[idx-1] else: idx_nearest = idx_sorted[idx] return idx_nearest


Si no quieres usar numpy esto lo hará:

def find_nearest(array, value): n = [abs(i-value) for i in array] idx = n.index(min(n)) return array[idx]


Todas las respuestas son beneficiosas para recopilar la información para escribir código eficiente. Sin embargo, he escrito un pequeño script de Python para optimizar varios casos. Será el mejor caso si se ordena la matriz proporcionada. Si se busca el índice del punto más cercano de un valor específico, el módulo bisect es el más eficiente en cuanto al tiempo. Cuando una búsqueda de los índices corresponde a una matriz, la numpy searchsorted es más eficiente.

import numpy as np import bisect xarr = np.random.rand(int(1e7)) srt_ind = xarr.argsort() xar = xarr.copy()[srt_ind] xlist = xar.tolist() bisect.bisect_left(xlist, 0.3)

En [63]:% de tiempo bisect.bisect_left (xlist, 0.3) tiempos de CPU: usuario 0 ns, sys: 0 ns, total: 0 ns Tiempo de pared: 22.2 µs

np.searchsorted(xar, 0.3, side="left")

En [64]:% time np.searchsorted (xar, 0.3, side = "left") tiempos de CPU: usuario 0 ns, sys: 0 ns, total: 0 ns Tiempo de pared: 98.9 µs

randpts = np.random.rand(1000) np.searchsorted(xar, randpts, side="left")

% time np.searchsorted (xar, randpts, side = "left") tiempos de CPU: usuario 4 ms, sys: 0 ns, total: 4 ms Tiempo de pared: 1.2 ms

Si seguimos la regla multiplicativa, entonces numpy debería tomar ~ 100 ms, lo que implica ~ 83X más rápido.


Si su matriz está ordenada y es muy grande, esta es una solución mucho más rápida:

def find_nearest(array,value): idx = np.searchsorted(array, value, side="left") if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])): return array[idx-1] else: return array[idx]

Esto escala a matrices muy grandes. Puede modificar fácilmente lo anterior para ordenar el método si no puede asumir que la matriz ya está ordenada. Es excesivo para los arreglos pequeños, pero una vez que se hacen grandes, esto es mucho más rápido.


Resumen de la respuesta : si uno tiene una array ordenada, entonces el código de bisección (que se muestra a continuación) es el que realiza la ejecución más rápida. ~ 100-1000 veces más rápido para arreglos grandes, y ~ 2-100 veces más rápido para arreglos pequeños. Tampoco requiere numpy. Si tiene una array sin clasificar, entonces si la array es grande, primero debe considerar usar una clasificación O (n logn) y luego la bisección, y si la array es pequeña, entonces el método 2 parece ser el más rápido.

Primero debes aclarar qué quieres decir con el valor más cercano . A menudo, uno quiere el intervalo en una abscisa, por ejemplo, matriz = [0,0.7,2.1], valor = 1.95, la respuesta sería idx = 1. Este es el caso que sospecho que necesita (de lo contrario, lo siguiente puede modificarse muy fácilmente con una declaración condicional de seguimiento una vez que encuentre el intervalo). Observaré que la forma óptima de realizar esto es con la bisección (que proporcionaré en primer lugar: no requiere ningún número y es más rápido que usar las funciones de números porque realizan operaciones redundantes). A continuación, proporcionaré una comparación de tiempo con los demás presentados aquí por otros usuarios.

Bisección:

def bisection(array,value): ''''''Given an ``array`` , and given a ``value`` , returns an index j such that ``value`` is between array[j] and array[j+1]. ``array`` must be monotonic increasing. j=-1 or j=len(array) is returned to indicate that ``value`` is out of range below and above respectively.'''''' n = len(array) if (value < array[0]): return -1 elif (value > array[n-1]): return n jl = 0# Initialize lower ju = n-1# and upper limits. while (ju-jl > 1):# If we are not yet done, jm=(ju+jl) >> 1# compute a midpoint with a bitshift if (value >= array[jm]): jl=jm# and replace either the lower limit else: ju=jm# or the upper limit, as appropriate. # Repeat until the test condition is satisfied. if (value == array[0]):# edge cases at bottom return 0 elif (value == array[n-1]):# and top return n-1 else: return jl

Ahora definiré el código de las otras respuestas, cada una de ellas devuelve un índice:

import math import numpy as np def find_nearest1(array,value): idx,val = min(enumerate(array), key=lambda x: abs(x[1]-value)) return idx def find_nearest2(array, values): indices = np.abs(np.subtract.outer(array, values)).argmin(0) return indices def find_nearest3(array, values): values = np.atleast_1d(values) indices = np.abs(np.int64(np.subtract.outer(array, values))).argmin(0) out = array[indices] return indices def find_nearest4(array,value): idx = (np.abs(array-value)).argmin() return idx def find_nearest5(array, value): idx_sorted = np.argsort(array) sorted_array = np.array(array[idx_sorted]) idx = np.searchsorted(sorted_array, value, side="left") if idx >= len(array): idx_nearest = idx_sorted[len(array)-1] elif idx == 0: idx_nearest = idx_sorted[0] else: if abs(value - sorted_array[idx-1]) < abs(value - sorted_array[idx]): idx_nearest = idx_sorted[idx-1] else: idx_nearest = idx_sorted[idx] return idx_nearest def find_nearest6(array,value): xi = np.argmin(np.abs(np.ceil(array[None].T - value)),axis=0) return xi

Ahora cronometraré los códigos: los métodos de nota 1,2,4,5 no dan el intervalo correctamente. Los métodos 1,2,4 redondean al punto más cercano en la matriz (por ejemplo,> = 1.5 -> 2), y el método 5 siempre se redondea (por ejemplo, 1.45 -> 2). Sólo los métodos 3 y 6, y por supuesto la bisección, dan el intervalo correctamente.

array = np.arange(100000) val = array[50000]+0.55 print( bisection(array,val)) %timeit bisection(array,val) print( find_nearest1(array,val)) %timeit find_nearest1(array,val) print( find_nearest2(array,val)) %timeit find_nearest2(array,val) print( find_nearest3(array,val)) %timeit find_nearest3(array,val) print( find_nearest4(array,val)) %timeit find_nearest4(array,val) print( find_nearest5(array,val)) %timeit find_nearest5(array,val) print( find_nearest6(array,val)) %timeit find_nearest6(array,val) (50000, 50000) 100000 loops, best of 3: 4.4 µs per loop 50001 1 loop, best of 3: 180 ms per loop 50001 1000 loops, best of 3: 267 µs per loop [50000] 1000 loops, best of 3: 390 µs per loop 50001 1000 loops, best of 3: 259 µs per loop 50001 1000 loops, best of 3: 1.21 ms per loop [50000] 1000 loops, best of 3: 746 µs per loop

Para una matriz grande, la bisección da 4us en comparación con el siguiente mejor 180us y 1.21ms más largo (~ 100 - 1000 veces más rápido). Para matrices más pequeñas es ~ 2-100 veces más rápido.


import numpy as np def find_nearest(array, value): array = np.array(array) z=np.abs(array-value) y= np.where(z == z.min()) m=np.array(y) x=m[0,0] y=m[1,0] near_value=array[x,y] return near_value array =np.array([[60,200,30],[3,30,50],[20,1,-50],[20,-500,11]]) print(array) value = 0 print(find_nearest(array, value))


import numpy as np def find_nearest(array, value): array = np.asarray(array) idx = (np.abs(array - value)).argmin() return array[idx] array = np.random.random(10) print(array) # [ 0.21069679 0.61290182 0.63425412 0.84635244 0.91599191 0.00213826 # 0.17104965 0.56874386 0.57319379 0.28719469] value = 0.5 print(find_nearest(array, value)) # 0.568743859261