Проверить, существует ли 2d массив в 3d массиве в Python? - PullRequest
0 голосов
/ 03 мая 2018

У меня есть 3d-массив с формой (1000, 12, 30), и у меня есть список 2-мерного массива формы (12, 30), и я хочу проверить, существуют ли эти 2-мерные массивы в 3d-массиве. Есть ли в Python простой способ сделать это? Я пробовал ключевое слово in, но оно не работает.

Ответы [ 3 ]

0 голосов
/ 03 мая 2018

Numpy

Учитывая

a = np.arange(12).reshape(3, 2, 2)
lst = [
    np.arange(4).reshape(2, 2),
    np.arange(4, 8).reshape(2, 2)
]

print(a, *lst, sep='\n{}\n'.format('-' * 20))

[[[ 0  1]
  [ 2  3]]

 [[ 4  5]
  [ 6  7]]

 [[ 8  9]
  [10 11]]]
--------------------
[[0 1]
 [2 3]]
--------------------
[[4 5]
 [6 7]]

Обратите внимание, что lst - это список массивов согласно OP. Я сделаю этот 3d массив b ниже.

Использовать трансляцию. Использование правил вещания. Я хочу, чтобы размеры a как (1, 3, 2, 2) и b как (2, 1, 2, 2).

b = np.array(lst)
x, *y = b.shape
c = np.equal(
    a.reshape(1, *a.shape),
    np.array(lst).reshape(x, 1, *y)
)

Я буду использовать all для получения (2, 3) массива значений истинности и np.where, чтобы выяснить, какие из подмассивов a и b фактически равны.

i, j = np.where(c.all((-2, -1)))

Это всего лишь подтверждение того, что мы достигли того, что хотели. Предполагается, что для каждого парного значения i и j подмассивы фактически одинаковы.

for t in zip(i, j):
    print(a[t[0]], b[t[1]], sep='\n\n')
    print('------')

[[0 1]
 [2 3]]

[[0 1]
 [2 3]]
------
[[4 5]
 [6 7]]

[[4 5]
 [6 7]]
------

in

Однако, чтобы завершить размышления ОП по использованию in

a_ = a.tolist()
list(filter(lambda x: x.tolist() in a_, lst))

[array([[0, 1],
        [2, 3]]), array([[4, 5],
        [6, 7]])]
0 голосов
/ 03 мая 2018

Вот быстрый метод (ранее использовался , @DanielF, а также как @jaime и другие, без сомнения), который использует трюк, чтобы извлечь выгоду из короткое замыкание: приведение блоков размера шаблона к отдельным элементам dtype void. При сравнении двух таких блоков Numpy останавливается после первой разницы, что дает огромное преимущество в скорости.

>>> def in_(data, template):
...     dv = data.reshape(data.shape[0], -1).view(f'V{data.dtype.itemsize*np.prod(data.shape[1:])}').ravel()
...     tv = template.ravel().view(f'V{template.dtype.itemsize*template.size}').reshape(())
...     return (dv==tv).any()

Пример:

>>> a = np.random.randint(0, 100, (1000, 12, 30))
>>> check = a[np.random.randint(0, 1000, (10,))]
>>> check += np.random.random(check.shape) < 0.001    
>>>
>>> [in_(a, c) for c in check]
[True, True, True, False, False, True, True, True, True, False]
# compare to other method
>>> (a==check[:, None]).all((-1,-2)).any(-1)
array([ True,  True,  True, False, False,  True,  True,  True,  True,
       False])

Дает тот же результат, что и "прямой", но почти в 20 раз быстрее:

>>> from timeit import timeit
>>> kwds = dict(globals=globals(), number=100)
>>> 
>>> timeit("(a==check[:, None]).all((-1,-2)).any(-1)", **kwds)
0.4793281531892717
>>> timeit("[in_(a, c) for c in check]", **kwds)
0.026218891143798828
0 голосов
/ 03 мая 2018

Есть способ в numpy, вы можете сделать с np.all

a=np.random.rand(3,1,2)
b=a[1][0]
np.all(np.all(a==b,1),1)
Out[612]: array([False,  True, False])

Раствор от bnaecker

np.all(a == b, axis=(1,2))

Если только хотите проверить выход или нет

np.any(np.all(a == b, axis=(1,2)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...