Удаление повторяющихся столбцов и строк из 2D-массива NumPy - PullRequest
20 голосов
/ 19 декабря 2011

Я использую массив фигур 2D для хранения пар долготы + широты.В какой-то момент мне нужно объединить два из этих двухмерных массивов, а затем удалить все дублированные записи.Я искал функцию, похожую на numpy.unique, но мне не повезло.Любая реализация, о которой я думал, выглядит очень «неоптимизированной».Например, я пытаюсь преобразовать массив в список кортежей, удалить дубликаты с помощью set, а затем снова преобразовать в массив:

coordskeys = np.array(list(set([tuple(x) for x in coordskeys])))

Существуют ли уже существующие решения, поэтому я не изобретаю зановоколесо?

Чтобы было понятно, я ищу:

>>> a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]])
>>> unique_rows(a)
array([[1, 1], [2, 3],[5, 4]])

Кстати, я хотел использовать для него просто список кортежей, но списки были настолько большими, чтоони использовали мою 4 Гб оперативной памяти + 4 Гб подкачки (числовые массивы более эффективно используют память).

Ответы [ 6 ]

31 голосов
/ 20 декабря 2011

Это должно сработать:

def unique_rows(a):
    a = np.ascontiguousarray(a)
    unique_a = np.unique(a.view([('', a.dtype)]*a.shape[1]))
    return unique_a.view(a.dtype).reshape((unique_a.shape[0], a.shape[1]))

Пример:

>>> a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]])
>>> unique_rows(a)
array([[1, 1],
       [2, 3],
       [5, 4]])
17 голосов
/ 19 декабря 2011

Вот одна из идей, это займет немного работы, но может быть довольно быстрым. Я дам вам 1-й случай и дам вам понять, как его расширить до 2-го. Следующая функция находит уникальные элементы массива 1d:

import numpy as np
def unique(a):
    a = np.sort(a)
    b = np.diff(a)
    b = np.r_[1, b]
    return a[b != 0]

Теперь, чтобы расширить его до 2d, вам нужно изменить две вещи. Вам нужно будет выяснить, как выполнить сортировку самостоятельно, важно, чтобы сортировка состояла в том, что две идентичные записи оказываются рядом друг с другом. Во-вторых, вам нужно сделать что-то вроде (b != 0).all(axis), потому что вы хотите сравнить всю строку / столбец. Дайте мне знать, если этого достаточно, чтобы вы начали.

обновлено: с некоторой помощью с Дагом, я думаю, это должно работать для 2-го случая.

import numpy as np
def unique(a):
    order = np.lexsort(a.T)
    a = a[order]
    diff = np.diff(a, axis=0)
    ui = np.ones(len(a), 'bool')
    ui[1:] = (diff != 0).any(axis=1) 
    return a[ui]
5 голосов
/ 28 ноября 2013

Мой метод состоит в том, чтобы превратить 2d массив в 1d комплексный массив, где действительная часть - 1-й столбец, мнимая часть - 2-й столбец. Тогда используйте np.unique. Хотя это будет работать только с 2 столбцами.

import numpy as np 
def unique2d(a):
    x, y = a.T
    b = x + y*1.0j 
    idx = np.unique(b,return_index=True)[1]
    return a[idx] 

Пример -

a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]])
unique2d(a)
array([[1, 1],
       [2, 3],
       [5, 4]])
3 голосов
/ 02 апреля 2016

Пакет numpy_indexed (отказ от ответственности: я его автор) оборачивает решение, опубликованное user545424, в приятный и проверенный интерфейс, а также множество связанных с ним функций:

import numpy_indexed as npi
npi.unique(coordskeys)
3 голосов
/ 20 декабря 2011
>>> import numpy as NP
>>> # create a 2D NumPy array with some duplicate rows
>>> A
    array([[1, 1, 1, 5, 7],
           [5, 4, 5, 4, 7],
           [7, 9, 4, 7, 8],
           [5, 4, 5, 4, 7],
           [1, 1, 1, 5, 7],
           [5, 4, 5, 4, 7],
           [7, 9, 4, 7, 8],
           [5, 4, 5, 4, 7],
           [7, 9, 4, 7, 8]])

>>> # first, sort the 2D NumPy array row-wise so dups will be contiguous
>>> # and rows are preserved
>>> a, b, c, d, e = A.T    # create the keys for to pass to lexsort
>>> ndx = NP.lexsort((a, b, c, d, e))
>>> ndx
    array([1, 3, 5, 7, 0, 4, 2, 6, 8])
>>> A = A[ndx,]

>>> # now diff by row
>>> A1 = NP.diff(A, axis=0)
>>> A1
    array([[0, 0, 0, 0, 0],
           [4, 3, 3, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 1, 0],
           [0, 0, 1, 0, 0],
           [2, 5, 0, 2, 1],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0]])

>>> # the index array holding the location of each duplicate row
>>> ndx = NP.any(A1, axis=1)  
>>> ndx
    array([False,  True, False,  True,  True,  True, False, False], dtype=bool)  

>>> # retrieve the duplicate rows:
>>> A[1:,:][ndx,]
    array([[7, 9, 4, 7, 8],
           [1, 1, 1, 5, 7],
           [5, 4, 5, 4, 7],
           [7, 9, 4, 7, 8]])
1 голос
/ 19 декабря 2011

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

>>> x = [(1, 1), (2, 3), (1, 1), (5, 4), (2, 3)]
>>> y = list(set(x))
>>> y
[(5, 4), (2, 3), (1, 1)]
>>> 
...