[英]How to determine in Python how many entries in an array are outside a given interval?
[英]How to efficiently determine the interval a given value is in?
考慮值x
的以下區域定義:
我正在尋找一種有效的方法來確定給定x
值的區域。 我提出了:
borders = (1, 10, 112)
tst_values = (.2, 2, 22, 222)
for x in tst_values:
z = next((i for b, i in zip(borders, 'ABC') if x < b), 'D')
print(f" * Value {x:3g} is in zone '{z}'.")
# The output is:
# * Value 0.2 is in zone 'A'.
# * Value 2 is in zone 'B'.
# * Value 22 is in zone 'C'.
# * Value 222 is in zone 'D'.
解決此類問題的最佳做法是什么,尤其是區域數量(即len(borders)
較大時。 borders
可能包含任意(增加)浮點數列表。
更新改寫的問題,以解決評論。
一種有效的方法是通過邊界進行二進制搜索。 Python有一個bisect
庫,可以為你完成這個:
import bisect
borders = (1, 10, 112)
tst_values = (.2, 2, 22, 222)
for x in tst_values:
border_right = bisect.bisect_right(borders, x) # x < b
# or
border_left = bisect.bisect_left(borders, x) # x > b
這將為您提供值x落入的邊界的索引。 如果您願意,可以將該索引轉換為字母。
為了有效地找到你在一長串排序邊界中的范圍,我建議使用二進制搜索 。 基本上,你看看你的邊界數組的中間,檢查你是否大/小。 根據具體情況,您可以檢查邊界陣列長度的一/四分之三的值。 等等。
這可以使用遞歸手動輕松實現。 或者,您可以使用numpy的實現numpy.digitize ,YSelf指出。 后者幾乎肯定會比前者更快。
使用numpy.digitize
,您的代碼將變為:
borders = (1, 10, 112)
values = (.2, 2, 22, 222)
for x in values:
z = 'ABCD'[numpy.digitize(x, borders)]
print(f" * Value {x:3g} is in zone '{z}'.")
如果你想有效的方法來解決此問題,使用使用numpy的矢量運算np.greater_than
和np.less
帶outer
,再服用指數值與np.take
a = np.greater_equal.outer(tst_values, [-np.inf, 1,10,112]) & \
np.less.outer(tst_values, [1, 10,112, np.inf])
np.take(list('ABCD'), np.argmax(a, axis=1))
這非常有效。 對於5 MM行,它在不到一秒的時間內運行
%timeit (...)
922 ms ± 8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.