Удаление строк с дубликатами в массиве NumPy - PullRequest
12 голосов
/ 16 сентября 2011

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

>>> 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 без зацикливания (массив может быть довольно большим).Кто-нибудь знает, как я мог это сделать?

Ответы [ 5 ]

10 голосов
/ 16 сентября 2011

Это опция:

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)
3 голосов
/ 17 июля 2017

Вот подход для обработки общего числа столбцов и все же метод векторизации -

def rows_uniq_elems(a):
    a_sorted = np.sort(a,axis=-1)
    return a[(a_sorted[...,1:] != a_sorted[...,:-1]).all(-1)]

Шаги:

  • Сортировка по каждой строке.

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

Пример выполнения -

In [49]: a
Out[49]: 
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 [50]: rows_uniq_elems(a)
Out[50]: 
array([[1, 2, 3, 7],
       [4, 5, 6, 7],
       [0, 4, 5, 6],
       [5, 4, 3, 2]])
2 голосов
/ 23 февраля 2018

Прошло шесть лет, но этот вопрос помог мне, поэтому я проверил сравнение скорости ответов Дивакара, Бенджамина, Марсело Кантоса и Кертиса Патрика.

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

def rows_uniq_elems1(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)]

def rows_uniq_elems2(a):
    a = (a[:,0] == a[:,1]) | (a[:,1] == a[:,2]) | (a[:,0] == a[:,2])
    return np.delete(a, np.where(a), axis=0)

def rows_uniq_elems3(a):
    return np.array([v for v in a if len(set(v)) == len(v)])

def rows_uniq_elems4(a):
    return np.array([v for v in a if len(np.unique(v)) == len(v)])

Результаты:

%timeit rows_uniq_elems1(vals)
10000 loops, best of 3: 67.9 µs per loop

%timeit rows_uniq_elems2(vals)
10000 loops, best of 3: 156 µs per loop

%timeit rows_uniq_elems3(vals)
1000 loops, best of 3: 59.5 µs per loop

%timeit rows_uniq_elems(vals)
10000 loops, best of 3: 268 µs per loop

Кажется, что использование set бьет numpy.unique. В моем случае мне нужно было сделать это через гораздо больший массив:

bigvals = np.random.randint(0,10,3000).reshape([3,1000])

%timeit rows_uniq_elems1(bigvals)
10000 loops, best of 3: 276 µs per loop

%timeit rows_uniq_elems2(bigvals)
10000 loops, best of 3: 192 µs per loop

%timeit rows_uniq_elems3(bigvals)
10000 loops, best of 3: 6.5 ms per loop

%timeit rows_uniq_elems4(bigvals)
10000 loops, best of 3: 35.7 ms per loop

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

РЕДАКТИРОВАНИЕ , поскольку я перепутал строки и столбцы в bigvals

2 голосов
/ 16 сентября 2011
numpy.array([v for v in vals if len(set(v)) == len(v)])

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

1 голос
/ 16 сентября 2011

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

numpy.array([v for v in vals if len(numpy.unique(v)) == len(v)])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...