2015-09-10 2 views
1

Как я могу найти пересечение двух 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: [] 
+1

Может ли вы описать проблему немного более ясно? То, что вы дали здесь, является правильным ответом: в двух списках нет общих элементов. – Prune

+0

@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] –

+1

Извините; Я не объяснил достаточно хорошо; Весь день я сталкиваюсь с проблемами округления. Я очень подозреваю, что вы получаете ряд значений больше, чем [2.0, 2.09999999998, 2.1999999999997, ...] Вы пробовали распечатать свой сгенерированный список с высокой точностью? Из того, что я помню, у intersect1d нет модификатора точности для «почтиEquals». Возможно, вам придется написать это самостоятельно. Другим способом является округление каждого элемента списка до такой же точности, как 5 десятичных знаков, а затем пересечение. – Prune

ответ

2

Положив мои комментарии в виде функции (предполагается, что оба списка сортируются, которые вы должны сделать загодя):

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: исправлена ​​ошибка

+0

Примечание: это все равно будет квадратичным, если все в обоих списках перекрывается в пределах допуска. Но в большинстве случаев я не думал, что это произойдет. –

+0

Возврат ovr_a, очевидно, представляет индексы совпадающих значений относительно списка a, но мне непонятно, что представляет ovr_b со значением [0, 2, 3]. –

+0

Я только что отредактировал, чтобы использовать islice вместо этого - он делает индекс более четким, а также избегает случая, когда b [start_b:] вернет копию –

4

Благодаря тому, как поплавки работу, в вашем примере а [3] не 2,3, а 2.3000000000000003. Это связано с тем, что 0,1 не имеет точного представления в полях с двойной точностью IEEE. Метод intersect1d в numpy действительно хорошо подходит для целых чисел. Чтобы решить эту проблему, вы должны реализовать свой собственный метод, который принимает допуски, чтобы решить, достаточно ли близки два поплавка.

0

Следующая процедура вернет индексы общих значений в пределах указанных допусков (-ов) относительно списка 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] 
+1

Если 'item_a' в настоящее время 2.7, вы знаете, что когда вы искали' b' против 2.6, что ничего в 'b' не было закрыто, вы можете отказаться от поиска. Аналогично, когда вы начинаете поиск 'a', вам нужно только протестировать первый элемент' b', пока не приблизитесь. Вы можете применить одни и те же рассуждения во внутреннем цикле и сломаться, как только вы потерпите неудачу, когда 'item_b' больше, чем' item_a'. Кроме того, вам не нужно начинать с начала 'b', когда вы провалились в последний раз, а' item_b' меньше, чем 'item_a'. –

+0

Также обратите внимание, что это легко изменить, чтобы возвращать перекрывающиеся значения, а не индексы. – Prune

+0

@Prune Да, хотя подпрограмма Джона Моллера была более эффективной, и я просто использовал ее и изменил ovr_a.append (i) на over_a.append (ai), чтобы вернуть значения. Это решило проблему, с которой я столкнулся, и был наиболее полезен. Что касается лучшего решения, я бы сказал, что решение Дивакара побеждает - оно лаконично и быстро. –

2

Вот Векторизованный подход с использованием 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]) 
+0

На самом деле вы можете использовать 'b [np.isclose (a [:, None], b) .any (0)]' также –

+1

Я также должен добавить, что это намного быстрее, чем мой метод. –

+0

@JohnMoeller О да! Это тоже должно работать, спасибо! :) – Divakar

 Смежные вопросы

  • Нет связанных вопросов^_^