Удаление строк с дубликатами в массиве NumPy

У меня есть массив (N,3) значений numpy:

>>> vals = numpy.array([[1,2,3],[4,5,6],[7,8,7],[0,4,5],[2,2,1],[0,0,0],[5,4,3]])
>>> vals
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 7],
       [0, 4, 5],
       [2, 2, 1],
       [0, 0, 0],
       [5, 4, 3]])

Я хочу удалить строки из массива с двойным значением. Например, результат для указанного массива должен быть:

>>> duplicates_removed
array([[1, 2, 3],
       [4, 5, 6],
       [0, 4, 5],
       [5, 4, 3]])

Я не уверен, как сделать это эффективно с помощью numpy без цикла (массив может быть довольно большим). Кто-нибудь знает, как я могу это сделать?

Ответ 1

Это вариант:

import numpy
vals = numpy.array([[1,2,3],[4,5,6],[7,8,7],[0,4,5],[2,2,1],[0,0,0],[5,4,3]])
a = (vals[:,0] == vals[:,1]) | (vals[:,1] == vals[:,2]) | (vals[:,0] == vals[:,2])
vals = numpy.delete(vals, numpy.where(a), axis=0)

Ответ 2

numpy.array([v for v in vals if len(set(v)) == len(v)])

Имейте в виду, что это все еще происходит за кулисами. Вы не можете этого избежать. Но он должен работать нормально даже для миллионов строк.

Ответ 3

Идентично Марсело, но я думаю, что использование numpy.unique() вместо set() может получить именно то, что вы стремитесь.

numpy.array([v for v in vals if len(numpy.unique(v)) == len(v)])

Ответ 4

Здесь используется подход для обработки общего числа столбцов и все еще быть векторизованным методом -

def rows_uniq_elems(a):
    idx = a.argsort(1)
    a_sorted = a[np.arange(idx.shape[0])[:,None], idx]
    return a[(a_sorted[:,1:] != a_sorted[:,:-1]).all(-1)]

Шаги:

  • Получить argsort индексы вдоль каждой строки.

  • Используйте advanced-indexing для сортировки каждой строки, предоставляя нам отсортированный по строкам массив.

  • Ищите различия между последовательными элементами в каждой строке. Таким образом, любая строка с хотя бы одним нулевым дифференцированием указывает на дублирующий элемент. Мы будем использовать это, чтобы получить маску допустимых строк. Итак, последний шаг - просто выбрать допустимые строки из входного массива, используя маску.

Пример прогона -

In [90]: a
Out[90]: 
array([[1, 2, 3, 7],
       [4, 5, 6, 7],
       [7, 8, 7, 8],
       [0, 4, 5, 6],
       [2, 2, 1, 1],
       [0, 0, 0, 3],
       [5, 4, 3, 2]])

In [91]: rows_uniq_elems(a)
Out[91]: 
array([[1, 2, 3, 7],
       [4, 5, 6, 7],
       [0, 4, 5, 6],
       [5, 4, 3, 2]])