Câu trả lời:
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.
Sử dụng idxmin
thay vì argmin
làm việc cho tôi với giải pháp trên. (
NẾU mảng của bạn được sắp xếp và rất lớn, đây là một giải pháp nhanh hơn nhiều:
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]
Quy mô này để mảng rất lớn. Bạn có thể dễ dàng sửa đổi phần trên để sắp xếp trong phương thức nếu bạn không thể cho rằng mảng đã được sắp xếp. Đó là quá mức cần thiết cho các mảng nhỏ, nhưng một khi chúng lớn, điều này nhanh hơn nhiều.
np.searchsorted
mất khoảng 2 bản vá cho bộ thử nghiệm của tôi, toàn bộ chức năng khoảng 10 bản. Sử dụng np.abs
nó thậm chí còn tồi tệ hơn. Không biết con trăn đang làm gì ở đó.
math
thói quen, xem câu trả lời này .
if/else
nhu cầu cần được thay thế bằngidx = idx - (np.abs(value - array[idx-1]) < np.abs(value - array[idx])); return array[idx]
value
lớn hơn array
yếu tố lớn nhất. Tôi đã thay đổi if
tuyên bố if idx == len(array) or math.fabs(value - array[idx - 1]) < math.fabs(value - array[idx])
để làm cho nó hoạt động cho tôi!
if idx > 0 and (idx == len(array) or math.fabs(value - array[idx-1]) < math.fabs(value - array[idx])):
Với một chút sửa đổi, câu trả lời ở trên hoạt động với các mảng có kích thước tùy ý (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]
Hoặc, được viết dưới dạng một dòng duy nhất:
a.flat[np.abs(a - a0).argmin()]
a[np.abs(a-a0).argmin)]
hoạt động tốt
a[np.sum(np.square(np.abs(a-a0)),1).argmin()]
.
Tóm tắt câu trả lời : Nếu ai đó đã sắp xếp array
thì mã chia đôi (được đưa ra dưới đây) thực hiện nhanh nhất. ~ 100-1000 lần nhanh hơn cho các mảng lớn và nhanh hơn ~ 2 - 100 lần cho các mảng nhỏ. Nó cũng không yêu cầu numpy. Nếu bạn có một loại chưa được sắp xếp array
thì nếu array
lớn, trước tiên bạn nên xem xét sử dụng sắp xếp O (n logn) và sau đó chia đôi, và nếuarray
nhỏ thì phương thức 2 có vẻ là nhanh nhất.
Trước tiên, bạn nên làm rõ những gì bạn có nghĩa là giá trị gần nhất . Thông thường người ta muốn khoảng trong một abscissa, ví dụ mảng = [0,0.7,2.1], value = 1.95, câu trả lời sẽ là idx = 1. Đây là trường hợp mà tôi nghi ngờ bạn cần (nếu không, những điều sau đây có thể được sửa đổi rất dễ dàng với một tuyên bố điều kiện tiếp theo một khi bạn tìm thấy khoảng). Tôi sẽ lưu ý rằng cách tối ưu để thực hiện việc này là chia đôi (mà tôi sẽ cung cấp trước - lưu ý rằng nó không yêu cầu numpy chút nào và nhanh hơn so với sử dụng các hàm numpy vì chúng thực hiện các hoạt động dự phòng). Sau đó, tôi sẽ cung cấp một so sánh thời gian so với những người khác được trình bày ở đây bởi những người dùng khác.
Sai lệch:
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
Bây giờ tôi sẽ xác định mã từ các câu trả lời khác, mỗi câu trả về một chỉ mục:
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
Bây giờ tôi sẽ tính thời gian cho các mã: Lưu ý các phương thức 1,2,4,5 không đưa ra khoảng thời gian chính xác. Các phương thức 1,2,4 làm tròn đến điểm gần nhất trong mảng (ví dụ> = 1,5 -> 2) và phương thức 5 luôn làm tròn (ví dụ: 1,45 -> 2). Chỉ có các phương pháp 3 và 6, và tất nhiên là chia đôi cho khoảng thời gian đúng.
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
Đối với một mảng lớn, chia 4us so với 180us tốt nhất tiếp theo và dài nhất 1,21ms (nhanh hơn 100 - 1000 lần). Đối với các mảng nhỏ hơn, nó nhanh hơn ~ 2 - 100 lần.
array
nhỏ thì phương pháp 2 có vẻ là nhanh nhất". bạn có ý nghĩa như thế nào @JoshAlbert?
Đây là một phần mở rộng để tìm vectơ gần nhất trong một mảng các vectơ.
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)
nên nhanh hơn trích xuất các x,y
giá trị thông qua Lặp lại Python. Ngoài ra, x,y
có vô hướng ở đây? Sau đó norm(x+y)
là một lỗi vì, ví dụ, khoảng cách (+1, -1)
sẽ được coi là 0.
idx = np.array([np.linalg.norm(x+y) for (x,y) in abs(array-value)]).argmin()
Nếu bạn không muốn sử dụng numpy, điều này sẽ làm điều đó:
def find_nearest(array, value):
n = [abs(i-value) for i in array]
idx = n.index(min(n))
return array[idx]
Đây là phiên bản sẽ xử lý mảng "giá trị" không vô hướng:
import numpy as np
def find_nearest(array, values):
indices = np.abs(np.subtract.outer(array, values)).argmin(0)
return array[indices]
Hoặc một phiên bản trả về kiểu số (ví dụ: int, float) nếu đầu vào là vô hướng:
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
phương pháp ufunc trước đây, tôi nghĩ rằng tôi sẽ sử dụng nó nhiều hơn trong tương lai. Nhân tiện, chức năng đầu tiên sẽ trở lại array[indices]
.
np.subtract.outer
sẽ tạo ra toàn bộ ma trận sản phẩm bên ngoài rất chậm và tốn nhiều bộ nhớ nếu array
và / hoặc values
rất lớn.
Đây là một phiên bản với scipy cho @Ari Onasafari, trả lời " để tìm vectơ gần nhất trong một mảng các vectơ "
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])
Đây là phiên bản được vector hóa nhanh của giải pháp @ Dimitri nếu bạn có nhiều thứ values
để tìm kiếm ( values
có thể là mảng đa chiều):
#`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]
Điểm chuẩn
> Nhanh hơn 100 lần so với sử dụng for
vòng lặp với giải pháp của @ 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
idx = np.searchsorted(array, values)
sau đó: idx[array[idx] - values>np.diff(array).mean()*0.5]-=1
và cuối cùngreturn array[idx]
Đối với mảng lớn, câu trả lời (xuất sắc) do @Demitri đưa ra nhanh hơn nhiều so với câu trả lời hiện được đánh dấu là tốt nhất. Tôi đã điều chỉnh thuật toán chính xác của mình theo hai cách sau:
Hàm bên dưới hoạt động cho dù mảng đầu vào có được sắp xếp hay không.
Hàm bên dưới trả về chỉ mục của mảng đầu vào tương ứng với giá trị gần nhất, có phần chung hơn.
Lưu ý rằng chức năng bên dưới cũng xử lý một trường hợp cạnh cụ thể sẽ dẫn đến lỗi trong chức năng ban đầu được viết bởi @Demitri. Nếu không, thuật toán của tôi là giống hệt của mình.
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])
. Với find_nearest(x, 1739.5)
(giá trị gần nhất với định lượng đầu tiên), tôi nhận được 1637
(hợp lý) và 1
(lỗi?).
Đây là phiên bản véc tơ của câu trả lời của 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)
Tôi nghĩ rằng cách pythonic nhất sẽ là:
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)
Đây là mã cơ bản. Bạn có thể sử dụng nó như một chức năng nếu bạn muốn
Tất cả các câu trả lời đều có lợi để thu thập thông tin để viết mã hiệu quả. Tuy nhiên, tôi đã viết một tập lệnh Python nhỏ để tối ưu hóa cho các trường hợp khác nhau. Nó sẽ là trường hợp tốt nhất nếu mảng được cung cấp được sắp xếp. Nếu một người tìm kiếm chỉ mục của điểm gần nhất của một giá trị được chỉ định, thì bisect
mô-đun là hiệu quả nhất về thời gian. Khi một tìm kiếm các chỉ số tương ứng với một mảng, numpy searchsorted
hiệu quả nhất.
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)
Trong [63]:% time bisect.bisect_left (xlist, 0.3) Thời gian CPU: người dùng 0 ns, sys: 0 ns, tổng: 0 ns Thời gian trên tường: 22.2.
np.searchsorted(xar, 0.3, side="left")
Trong [64]:% time np.searchsort (xar, 0.3, side = "left") Thời gian CPU: người dùng 0 ns, sys: 0 ns, tổng: 0 ns Thời gian trên tường: 98.9.
randpts = np.random.rand(1000)
np.searchsorted(xar, randpts, side="left")
% time np.searchsort (xar, randpts, side = "left") Thời gian CPU: người dùng 4 ms, sys: 0 ns, tổng cộng: 4 ms Thời gian trên tường: 1,2 ms
Nếu chúng ta tuân theo quy tắc nhân, thì numpy sẽ mất ~ 100 ms nghĩa là nhanh hơn 83 lần.
Đối với mảng 2d, để xác định vị trí i, j của phần tử gần nhất:
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))
Có thể hữu ích cho ndarrays
:
def find_nearest(X, value):
return X[np.unravel_index(np.argmin(np.abs(X - value)), X.shape)]
return np.abs(array-value).min()
đưa ra câu trả lời sai. Điều này cung cấp cho bạn tối thiểu khoảng cách giá trị tuyệt đối và bằng cách nào đó chúng ta cần trả về giá trị mảng thực tế. Chúng ta có thể thêmvalue
và đến gần, nhưng giá trị tuyệt đối ném cờ lê vào mọi thứ ...