답변:
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
FutureWarning: 'argmin' is deprecated. Use 'idxmin' instead. The behavior of 'argmin' will be corrected to return the positional minimum in the future. Use 'series.values.argmin' to get the position of the minimum now.
위의 솔루션으로 나를 idxmin
대신 사용 argmin
하십시오. (v3.6.4)
경우 배열을 정렬하고 매우 큰되고, 이것은 훨씬 빠른 솔루션입니다 :
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]
이것은 매우 큰 배열로 확장됩니다. 배열이 이미 정렬되어 있다고 가정 할 수없는 경우 위의 방법으로 정렬하여 쉽게 정렬 할 수 있습니다. 작은 어레이에는 과잉이지만, 일단 커지면 훨씬 빠릅니다.
np.searchsorted
테스트 세트에 일반 은 약 2 µs, 전체 기능은 약 10 µs입니다. np.abs
그것을 사용 하면 점점 악화되고 있습니다. 파이썬이 무엇을하고 있는지 전혀 알지 못합니다.
if/else
를 다음과 같이 교체해야합니다.idx = idx - (np.abs(value - array[idx-1]) < np.abs(value - array[idx])); return array[idx]
value
보다 크면 작동하지 않습니다 array
. 나는 그 if
진술이 if idx == len(array) or math.fabs(value - array[idx - 1]) < math.fabs(value - array[idx])
나를 위해 작동하도록 변경했습니다 !
if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])):
약간 수정하면 위의 대답은 임의의 차원 (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]
또는 한 줄로 작성하십시오.
a.flat[np.abs(a - a0).argmin()]
a[np.abs(a-a0).argmin)]
잘 작동합니다.
a[np.sum(np.square(np.abs(a-a0)),1).argmin()]
.
답변 요약 : 정렬 된 array
경우 이분법 코드 (아래 제공)가 가장 빠릅니다. 대형 어레이의 경우 ~ 100-1000 배, 소형 어레이의 경우 ~ 2-100 배 더 빠릅니다. numpy도 필요하지 않습니다. 분류되지 않은 array
경우 array
큰 경우 먼저 O (n logn) 정렬을 사용한 다음 이분법을 고려해야하며, array
작 으면 방법 2가 가장 빠릅니다.
먼저 가장 가까운 값으로 의미를 명확히해야합니다 . 가로축의 간격을 원할 때가 종종 있습니다 (예 : array = [0,0.7,2.1], value = 1.95, answer는 idx = 1입니다. 이것은 내가 필요하다고 생각하는 경우입니다 (그렇지 않으면 간격을 찾으면 후속 조건문을 사용하여 다음을 매우 쉽게 수정할 수 있습니다). 이 작업을 수행하는 최적의 방법은 이분법을 사용하는 것입니다 (먼저 제공 할 것입니다-전혀 numpy가 필요하지 않으며 중복 작업을 수행하기 때문에 numpy 함수를 사용하는 것보다 빠릅니다). 그런 다음 다른 사용자가 여기에 제시 한 다른 것과의 타이밍 비교를 제공합니다.
이등분:
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
이제 다른 답변에서 코드를 정의하고 각각 인덱스를 반환합니다.
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
이제 코드의 시간을 정하겠습니다. 참고 방법 1,2,4,5는 간격을 올바르게 지정하지 않습니다. 방법 1,2,4는 배열에서 가장 가까운 점으로 반올림하고 (예 :> = 1.5-> 2), 방법 5는 항상 반올림합니다 (예 : 1.45-> 2). 방법 3, 6 및 물론 이분법 만 구간을 적절하게 제공합니다.
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
큰 배열의 이분법은 다음 최고 180us 및 가장 긴 1.21ms (~ 100-1000 배 더 빠름)에 비해 4us를 제공합니다. 더 작은 어레이의 경우 ~ 2-100 배 빠릅니다.
array
작은 경우 방법 2가 가장 빠른 것 같습니다." @JoshAlbert는 얼마나 작습니까?
다음은 벡터 배열에서 가장 가까운 벡터를 찾는 확장 기능입니다.
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])
norm(..., axis=-1)
추출하는 것보다 빠를 것이라고 생각 합니다 x,y
. 또한 x,y
스칼라가 있습니까? 그 다음 norm(x+y)
부터 버그, 예를 들어, 거리가 (+1, -1)
0으로 처리됩니다
idx = np.array([np.linalg.norm(x+y) for (x,y) in abs(array-value)]).argmin()
스칼라 이외의 "값"배열을 처리하는 버전은 다음과 같습니다.
import numpy as np
def find_nearest(array, values):
indices = np.abs(np.subtract.outer(array, values)).argmin(0)
return array[indices]
또는 입력이 스칼라 인 경우 숫자 유형 (예 : int, float)을 반환하는 버전 :
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]
outer
ufunc 방법을 사용한 적이 없으며 앞으로 더 많이 사용할 것입니다. 그런데 첫 번째 함수는를 반환해야합니다 array[indices]
.
np.subtract.outer
집중 정말 느리고 메모리의 경우 전체 외 - 매트릭스 생성 array
및 / 또는 values
매우 큰입니다.
다음은 @Ari Onasafari의 scipy 버전입니다. " 벡터 배열에서 가장 가까운 벡터를 찾으려면 "
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])
values
검색 할 것이 많은 경우 ( values
다차원 배열 일 수 있음) @Dimitri 솔루션의 빠른 벡터화 된 버전은 다음과 같습니다 .
#`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]
벤치 마크
for
@Demitri의 솔루션으로 루프를 사용하는 것보다 100 배 빠름
>>> %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
idx = np.searchsorted(array, values)
그러면 idx[array[idx] - values>np.diff(array).mean()*0.5]-=1
마지막으로return array[idx]
큰 배열의 경우 @Demitri가 제공하는 (우수한) 답변이 현재 최고로 표시된 답변보다 훨씬 빠릅니다. 나는 그의 정확한 알고리즘을 다음 두 가지 방식으로 조정했습니다.
아래 함수는 입력 배열의 정렬 여부에 관계없이 작동합니다.
아래 함수 는 가장 일반적인 값에 해당하는 입력 배열 의 인덱스 를 반환합니다 .
아래 함수는 @Demitri가 작성한 원래 함수의 버그로 이어질 수있는 특정 경우를 처리합니다. 그렇지 않으면 내 알고리즘은 그의 알고리즘과 동일합니다.
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
x = np.array([2038, 1758, 1721, 1637, 2097, 2047, 2205, 1787, 2287, 1940, 2311, 2054, 2406, 1471, 1460])
. find_nearest(x, 1739.5)
(첫 번째 Quantile에 가장 가까운 값)을 사용하면 ( 1637
합리적) 및 1
(버그?)를 얻습니다 .
이것은 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)
가장 파이썬적인 방법은 다음과 같습니다.
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)
이것이 기본 코드입니다. 원하는 경우 함수로 사용할 수 있습니다
모든 답변은 정보를 수집하여 효율적인 코드를 작성하는 데 도움이됩니다. 그러나 다양한 사례에 맞게 작은 Python 스크립트를 작성했습니다. 제공된 배열이 정렬 된 경우가 가장 좋습니다. 지정된 값의 가장 가까운 지점의 색인을 검색 bisect
하면 가장 시간 효율적인 모듈입니다. 하나의 검색 인덱스가 배열에 해당 numpy searchsorted
하면 가장 효율적입니다.
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)
[63]에서 : % time bisect.bisect_left (xlist, 0.3) CPU 시간 : 사용자 0ns, sys : 0ns, 총계 : 0ns 벽면 시간 : 22.2µs
np.searchsorted(xar, 0.3, side="left")
[64]에서 : % time np.searchsorted (xar, 0.3, side = "left") CPU 시간 : 사용자 0 ns, sys : 0 ns, 총계 : 0 ns 월 시간 : 98.9 µs
randpts = np.random.rand(1000)
np.searchsorted(xar, randpts, side="left")
% time np.searchsorted (xar, randpts, side = "left") CPU 시간 : 사용자 4ms, 시스템 : 0ns, 총계 : 4ms 월 시간 : 1.2ms
곱셈 규칙을 따르면 numpy는 ~ 100ms가 걸리므로 ~ 83X가 더 빠릅니다.
2D 배열의 경우 가장 가까운 요소의 i, j 위치를 결정하려면 다음을 수행하십시오.
import numpy as np
def find_nearest(a, a0):
idx = (np.abs(a - a0)).argmin()
w = a.shape[1]
i = idx // w
j = idx - i * w
return a[i,j], i, j
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))
return np.abs(array-value).min()
잘못된 대답을 제공합니다. 이를 통해 절대 값 거리의 최소값을 얻을 수 있으며 실제 배열 값을 반환해야합니다. 우리는 더해서value
가까이 다가올 수는 있지만 절대 값은 렌치를 사물에 던져 넣습니다.