#python #list #numpy
#python #Список #numpy
Вопрос:
Я ищу векторизованную функцию, которая возвращает маску со значениями True, если значение в массиве было замечено ранее, и False в противном случае.
Я ищу максимально быстрое решение, поскольку скорость очень важна.
Например, это то, что я хотел бы видеть:
array = [1, 2, 1, 2, 3]
mask = [False, False, True, True, False]
Так is_duplicate = array[mask]
должно вернуться [1, 2]
.
Есть ли быстрый, векторизованный способ сделать это? Спасибо!
Комментарии:
1. достигается ли конечная цель
[1, 2]
или вас конкретно интересует[False, False, True, True, False]
?2. Цель на самом деле заключается в дедупликации! Но у меня есть массив, в котором мне нужно дедуплицировать разделы массива. Например, мой массив может быть
array = [1, 2, 1, 2, 1, 2]
таким, в котором мне может потребоваться дедупликацияarray[0:4]
иarray[4:6]
получение[1, 2, 1, 2]
. Вот почему я хочу создать маску, но с удовольствием рассмотрю другие способы.
Ответ №1:
Подход № 1: с сортировкой
def mask_firstocc(a):
sidx = a.argsort(kind='stable')
b = a[sidx]
out = np.r_[False,b[:-1] == b[1:]][sidx.argsort()]
return out
Мы можем использовать array-assignment
для повышения производительности. далее —
def mask_firstocc_v2(a):
sidx = a.argsort(kind='stable')
b = a[sidx]
mask = np.r_[False,b[:-1] == b[1:]]
out = np.empty(len(a), dtype=bool)
out[sidx] = mask
return out
Пример запуска —
In [166]: a
Out[166]: array([2, 1, 1, 0, 0, 4, 0, 3])
In [167]: mask_firstocc(a)
Out[167]: array([False, False, True, False, True, False, True, False])
Подход № 2: с np.unique(..., return_index)
Мы можем использовать np.unique
его return_index
, который, по-видимому, возвращает первое вхождение каждого уникального элемента, следовательно, простое присвоение массива, а затем индексация работает —
def mask_firstocc_with_unique(a):
mask = np.ones(len(a), dtype=bool)
mask[np.unique(a, return_index=True)[1]] = False
return mask
Комментарии:
1. Спасибо за ответ! На самом деле я немного отредактировал свой вопрос, прежде всего я ищу решение numpy, потому что в этом пакете нет pandas в качестве требования, только numpy и scipy. Есть ли что-то подобное в numpy? Спасибо!
2. Это здорово, я использовал вашу mask_firstocc_v2, спасибо 🙂
Ответ №2:
Используйте np.unique
a = np.array([1, 2, 1, 2, 3])
_, ix = np.unique(a, return_index=True)
b = np.full(a.shape, True)
b[ix] = False
In [45]: b
Out[45]: array([False, False, True, True, False])
Комментарии:
1. Номера времени выполнения для unique и argsort одинаковы. Подумайте и об уникальных сортировках.
2. Это работает, хотя unique кажется немного медленнее, а сортировка работает лучше для моего варианта использования. Спасибо 🙂
Ответ №3:
Вы можете добиться этого с помощью enumerate
метода, который позволяет вам выполнять цикл с помощью index value
:
array = [1, 2, 1, 2, 3]
mask = []
for i,v in enumerate(array):
if array.index(v) == i:
mask.append(False)
else:
mask.append(True)
print(mask)
Вывод:
[False, False, True, True, False]
Ответ №4:
Почти по определению это нельзя векторизовать. Значение mask для any index
зависит от значения array
для каждого значения между 0 и index
. Может быть какой-то алгоритм, в котором вы расширяетесь array
до матрицы NxN и выполняете сложные тесты, но у вас все равно будет алгоритм O (n ^ 2). Простой алгоритм набора — O(n log n) .