Простой способ проверить, идентичны ли два образца в тензоре - PullRequest
1 голос
/ 05 апреля 2019

Некоторые примеры:

import numpy as np
tensor_same = np.array([[1]*10 + [2] * 10 + [1] * 10]).reshape((-1, 10, 1))
tensor_diff = np.array([[1]*10 + [2] * 10 + [1] * 9 + [2]]).reshape((-1, 10, 1))

Первый тензор имеет две одинаковые выборки.Во втором случае все образцы разные.

Какой самый быстрый способ проверить это для очень больших тензоров?

1 Ответ

1 голос
/ 05 апреля 2019

Мы можем использовать np.unique вдоль первой оси, чтобы получить уникальное количество блоков и, если оно совпадает с количеством элементов в исходном вводе, это будет указывать на все разные выборки, в противном случае, по крайней мере, один дубликат, например, -

In [25]: len(np.unique(tensor_same,axis=0)) != len(tensor_same)
Out[25]: True

In [26]: len(np.unique(tensor_diff,axis=0)) != len(tensor_diff)
Out[26]: False

Другой способ - использовать счетчики, возвращаемые np.unique -

In [42]: (np.unique(tensor_same,axis=0, return_counts=1)[1]>1).any()
Out[42]: True

In [43]: (np.unique(tensor_diff,axis=0, return_counts=1)[1]>1).any()
Out[43]: False

Другим способом будет сортировка по первой оси, последовательное дифференцирование элементов, а затем поиск всех нулей вдоль второй оси и, наконец, ANY match -

In [29]: (np.diff(np.sort(tensor_same,axis=0),axis=0)==0).all(1).any()
Out[29]: True

In [30]: (np.diff(np.sort(tensor_diff,axis=0),axis=0)==0).all(1).any()
Out[30]: False

Другим способом было бы использовать views так, чтобы каждый 2D блок рассматривался как один элемент каждый, а затем мы использовали одинаковую сортировку и искали идентичные последовательные элементы, например, так: *

# https://stackoverflow.com/a/44999009/ @Divakar
def view1D(a): # a is array
    a = np.ascontiguousarray(a)
    void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
    return a.view(void_dt).ravel()

def is_any_identical(a):
    a1D = view1D(a.reshape(a.shape[0],-1))
    a1Ds = np.sort(a1D)
    return (a1Ds[:-1] == a1Ds[1:]).any()

Пробный прогон -

In [90]: np.random.seed(0)
    ...: a = np.random.randint(11,99,(6,4,3))

In [91]: is_any_identical(a)
Out[91]: False

In [92]: a[2] = a[1] # force one identical element

In [93]: is_any_identical(a)
Out[93]: True

Для положительного ints, в качестве альтернативы, мы можем использовать np.einsum, чтобы получить то же самое уменьшение размерности, и в конечном итоге получить по одному элементу для каждого блока 2D. Следовательно, у нас будет a1D эквивалент в is_any_identical(), как, например, -

a1D = np.einsum('ijk,jk->i',a,a.max(0)+1)
...