มีวิธี numpy-thonic เช่นฟังก์ชันเพื่อหาค่าที่ใกล้ที่สุดในอาร์เรย์หรือไม่
ตัวอย่าง:
np.find_nearest( array, value )
มีวิธี numpy-thonic เช่นฟังก์ชันเพื่อหาค่าที่ใกล้ที่สุดในอาร์เรย์หรือไม่
ตัวอย่าง:
np.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
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]
ปรับขนาดเป็นอาร์เรย์ขนาดใหญ่มาก คุณสามารถปรับเปลี่ยนข้างต้นเพื่อจัดเรียงในวิธีการได้อย่างง่ายดายถ้าคุณไม่สามารถสันนิษฐานได้ว่าอาร์เรย์นั้นเรียงลำดับแล้ว มัน overkill สำหรับอาร์เรย์ขนาดเล็ก แต่เมื่อพวกเขามีขนาดใหญ่มันจะเร็วกว่ามาก
np.searchsorted
ใช้เวลาประมาณ 2 fors สำหรับชุดทดสอบของฉันฟังก์ชั่นทั้งหมดประมาณ 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
แล้วรหัส bisection (รับด้านล่าง) ดำเนินการเร็วที่สุด ~ 100-1000 ครั้งเร็วขึ้นสำหรับอาร์เรย์ขนาดใหญ่และ ~ 2-100 ครั้งเร็วขึ้นสำหรับอาร์เรย์ขนาดเล็ก มันไม่จำเป็นต้องมี numpy เช่นกัน หากคุณมีการเรียงลำดับไม่ได้array
หากarray
มีขนาดใหญ่คุณควรพิจารณาใช้ O (n logn) sort ก่อนแล้วจึงแบ่งออกเป็นสองส่วนและหากarray
มีขนาดเล็กวิธีที่ 2 ดูเหมือนจะเร็วที่สุด
แรกที่คุณควรอธิบายสิ่งที่คุณหมายถึงค่าที่ใกล้ที่สุด บ่อยครั้งที่หนึ่งต้องการช่วงเวลาใน abscissa เช่น array = [0,0.7,2.1], value = 1.95, คำตอบจะเป็น idx = 1 นี่เป็นกรณีที่ฉันสงสัยว่าคุณต้องการ (ไม่เช่นนั้นสามารถแก้ไขได้อย่างง่ายดายด้วยคำสั่งเงื่อนไขการติดตามเมื่อคุณพบช่วงเวลา) ฉันจะทราบว่าวิธีที่ดีที่สุดในการทำสิ่งนี้คือการแบ่งออกเป็นสองส่วน (ซึ่งฉันจะให้ไว้ก่อน - โปรดทราบว่ามันไม่จำเป็นต้องมี numpy เลยและเร็วกว่าการใช้ฟังก์ชั่น numpy เพราะมันทำหน้าที่ซ้ำซ้อน) จากนั้นฉันจะให้การเปรียบเทียบเวลากับผู้อื่นที่นำเสนอที่นี่โดยผู้ใช้รายอื่น
Bisection:
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
สำหรับการแบ่งอาร์เรย์ขนาดใหญ่ให้ 4us เมื่อเทียบกับ 180us ที่ดีที่สุดถัดไปและยาวที่สุด 1.21ms (เร็วกว่า 100 ~ 1,000 ครั้ง) สำหรับอาร์เรย์ขนาดเล็กมันเร็วกว่า ~ 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
ค่าผ่านการทำซ้ำของ Python นอกจากนี้ยังx,y
มีสเกลาที่นี่? จากนั้นnorm(x+y)
เป็นข้อผิดพลาดตั้งแต่เช่นระยะทาง(+1, -1)
จะได้รับการปฏิบัติเช่นเดียวกับ 0.
idx = np.array([np.linalg.norm(x+y) for (x,y) in abs(array-value)]).argmin()
หากคุณไม่ต้องการใช้สิ่งนี้จะทำ:
def find_nearest(array, value):
n = [abs(i-value) for i in array]
idx = n.index(min(n))
return array[idx]
นี่คือเวอร์ชันที่จะจัดการกับอาร์เรย์ "values" ที่ไม่ใช่สเกลาร์:
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
มีขนาดใหญ่มาก
นี่คือรุ่นที่มี scipy สำหรับ @Ari Onasafari ให้ตอบ " เพื่อค้นหาเวกเตอร์ที่ใกล้ที่สุดในอาร์เรย์ของเวกเตอร์ "
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])
นี่เป็นเวอร์ชันเวกเตอร์ที่รวดเร็วของโซลูชัน @ Dimitri หากคุณมีหลายสิ่งที่values
จะค้นหา ( values
สามารถเป็นอาร์เรย์หลายมิติ):
#`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)
(ค่าที่ใกล้เคียงที่สุดกับควอไทล์แรก) ฉันได้รับ 1637
(สมเหตุสมผล) และ1
(บั๊ก?)
นี่เป็นเวอร์ชัน vectorized ของคำตอบของ 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)
ฉันคิดว่าวิธี pythonic ที่สุดจะเป็น:
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]:% เวลา bisect.bisect_left (xlist, 0.3) เวลาซีพียู: ผู้ใช้ 0 ns, sys: 0 ns, ทั้งหมด: 0 ns เวลาผนัง: 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")
% เวลา np.searchsorted (xar, randpts, side = "left") เวลาซีพียู: ผู้ใช้ 4 ms, sys: 0 ns, ทั้งหมด: 4 ms Wall time: 1.2 ms
หากเราปฏิบัติตามกฎทวีคูณคุณควรใช้เวลาประมาณ ~ 100 ms ซึ่งหมายถึง ~ 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))
อาจเป็นประโยชน์สำหรับ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()
ให้คำตอบที่ผิด นี่จะให้ระยะทางต่ำสุดของค่าสัมบูรณ์กับคุณและเราต้องการคืนค่าอาร์เรย์จริง เราสามารถเพิ่มvalue
และมาใกล้ แต่ค่าสัมบูรณ์พ่นประแจเข้าไปในสิ่งที่ ...