回答:
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)
IFあなたの配列がソートされ、非常に大きいが、これははるかに高速なソリューションです。
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
私のテストセットでは、Plain は約2 µsかかり、機能全体は約10 µsです。np.abs
それを使用するとさらに悪化します。pythonがそこで何をしているのかわかりません。
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]
または、1行で記述します。
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)の並べ替えを使用してから2等分することを検討する必要がarray
あります。小さい場合は、方法2が最も高速のようです。
最初に、最も近い値によって何を意味するかを明確にする必要があります。多くの場合、横座標の間隔が必要です。たとえば、array = [0,0.7,2.1]、value = 1.95、答えは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
大規模なアレイの場合、二等分すると4usが得られ、次に良いのは180usで、最長の1.21msです(100〜1000倍高速)。小さいアレイの場合は、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()
numpyを使用したくない場合は、次のようにします。
def find_nearest(array, value):
n = [abs(i-value) for i in array]
idx = n.index(min(n))
return array[idx]
以下は、非スカラーの「値」配列を処理するバージョンです。
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によって与えられた(優れた)回答は、現在最良とマークされている回答よりもはるかに高速です。彼の正確なアルゴリズムを次の2つの方法で適合させました。
以下の関数は、入力配列がソートされているかどうかに関係なく機能します。
以下の関数は、最も一般的な値である最も近い値に対応する入力配列のインデックスを返します。
以下の関数は、@ 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
(バグ?)。
これは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
モジュールは最も時間効率が良いです。1回の検索でインデックスが配列に対応する場合、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時間:ユーザー0 ns、システム:0 ns、合計:0 nsウォール時間:22.2 µs
np.searchsorted(xar, 0.3, side="left")
In [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時間:ユーザー4 ms、sys:0 ns、合計:4 msウォール時間:1.2 ms
乗法則に従う場合、numpyは最大100ミリ秒かかります。これは、最大83倍高速であることを意味します。
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
して接近することはできますが、絶対値は物事にレンチを投げます...