Как я могу найти пересечение двух Numpy флоат массивов ?:Найти пересечение Numpy флоат массивов
a = np.arange(2, 3, 0.1)
b = np.array([2.3, 2.4, 2.5])
out_data = np.intersect1d(a, b)
результат является
out_data -> ndarray: []
Как я могу найти пересечение двух Numpy флоат массивов ?:Найти пересечение Numpy флоат массивов
a = np.arange(2, 3, 0.1)
b = np.array([2.3, 2.4, 2.5])
out_data = np.intersect1d(a, b)
результат является
out_data -> ndarray: []
Положив мои комментарии в виде функции (предполагается, что оба списка сортируются, которые вы должны сделать загодя):
import numpy as np
from itertools import islice
def findOverlap(self, a, b, rtol = 1e-05, atol = 1e-08):
ovr_a = []
ovr_b = []
start_b = 0
for i, ai in enumerate(a):
for j, bj in islice(enumerate(b), start_b, None):
if np.isclose(ai, bj, rtol=rtol, atol=atol, equal_nan=False):
ovr_a.append(i)
ovr_b.append(j)
elif bj > ai: # (more than tolerance)
break # all the rest will be farther away
else: # bj < ai (more than tolerance)
start_b += 1 # ignore further tests of this item
return (ovr_a, ovr_b)
EDIT: избавившись от equal_nan
- если вы собираетесь сортировать, вы можете также вырезать nans
EDIT: используя islice вместо o е срезы массива
EDIT: исправлена ошибка
Примечание: это все равно будет квадратичным, если все в обоих списках перекрывается в пределах допуска. Но в большинстве случаев я не думал, что это произойдет. –
Возврат ovr_a, очевидно, представляет индексы совпадающих значений относительно списка a, но мне непонятно, что представляет ovr_b со значением [0, 2, 3]. –
Я только что отредактировал, чтобы использовать islice вместо этого - он делает индекс более четким, а также избегает случая, когда b [start_b:] вернет копию –
Благодаря тому, как поплавки работу, в вашем примере а [3] не 2,3, а 2.3000000000000003. Это связано с тем, что 0,1 не имеет точного представления в полях с двойной точностью IEEE. Метод intersect1d
в numpy действительно хорошо подходит для целых чисел. Чтобы решить эту проблему, вы должны реализовать свой собственный метод, который принимает допуски, чтобы решить, достаточно ли близки два поплавка.
Следующая процедура вернет индексы общих значений в пределах указанных допусков (-ов) относительно списка a.
def findOverlap(self, a, b, rtol = 1e-05, atol = 1e-08, equal_nan = False):
overlap_indexes = []
for i, item_a in enumerate(a):
for item_b in b:
if np.isclose(item_a, item_b, rtol = rtol, atol = atol, equal_nan = equal_nan):
overlap_indexes.append(i)
return overlap_indexes
например
a = np.arange(2, 3, 0.1).tolist()
b = np.array([2.3, 2.4, 2.5]).tolist()
self.findOverlap(a, b)
-> overlap_indexes:[3, 4, 5]
Если 'item_a' в настоящее время 2.7, вы знаете, что когда вы искали' b' против 2.6, что ничего в 'b' не было закрыто, вы можете отказаться от поиска. Аналогично, когда вы начинаете поиск 'a', вам нужно только протестировать первый элемент' b', пока не приблизитесь. Вы можете применить одни и те же рассуждения во внутреннем цикле и сломаться, как только вы потерпите неудачу, когда 'item_b' больше, чем' item_a'. Кроме того, вам не нужно начинать с начала 'b', когда вы провалились в последний раз, а' item_b' меньше, чем 'item_a'. –
Также обратите внимание, что это легко изменить, чтобы возвращать перекрывающиеся значения, а не индексы. – Prune
@Prune Да, хотя подпрограмма Джона Моллера была более эффективной, и я просто использовал ее и изменил ovr_a.append (i) на over_a.append (ai), чтобы вернуть значения. Это решило проблему, с которой я столкнулся, и был наиболее полезен. Что касается лучшего решения, я бы сказал, что решение Дивакара побеждает - оно лаконично и быстро. –
Вот Векторизованный подход с использованием NumPy's broadcasting capability
-
tol = 1e-5 # tolerance
out = b[(np.abs(a[:,None] - b) < tol).any(0)]
Sample пробега -
In [31]: a
Out[31]: array([ 2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9])
In [32]: b
Out[32]: array([ 2.3 , 2.4 , 2.5 , 2.25, 2.1 ])
In [33]: tol = 1e-5 # tolerance
In [34]: b[(np.abs(a[:,None] - b) < tol).any(0)]
Out[34]: array([ 2.3, 2.4, 2.5, 2.1])
На самом деле вы можете использовать 'b [np.isclose (a [:, None], b) .any (0)]' также –
Я также должен добавить, что это намного быстрее, чем мой метод. –
@JohnMoeller О да! Это тоже должно работать, спасибо! :) – Divakar
Может ли вы описать проблему немного более ясно? То, что вы дали здесь, является правильным ответом: в двух списках нет общих элементов. – Prune
@Prune Возможно, я вижу вещи, но мне кажется, что 2.3, 2.4, 2.5 являются общими для a и b: a -> ndarray: [2. 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9], b -> ndarray: [2.3 2.4 2.5] –
Извините; Я не объяснил достаточно хорошо; Весь день я сталкиваюсь с проблемами округления. Я очень подозреваю, что вы получаете ряд значений больше, чем [2.0, 2.09999999998, 2.1999999999997, ...] Вы пробовали распечатать свой сгенерированный список с высокой точностью? Из того, что я помню, у intersect1d нет модификатора точности для «почтиEquals». Возможно, вам придется написать это самостоятельно. Другим способом является округление каждого элемента списка до такой же точности, как 5 десятичных знаков, а затем пересечение. – Prune