it-swarm-pt.tech

Removendo colunas e linhas duplicadas de uma matriz NumPy 2D

Estou usando uma matriz de formas 2D para armazenar pares de longitudes + latitudes. Em um ponto, eu tenho que mesclar duas dessas matrizes 2D e remover qualquer entrada duplicada. Estive procurando por uma função semelhante ao numpy.unique, mas não tive sorte. Qualquer implementação em que estive pensando parece muito "não otimizada". Por exemplo, estou tentando converter a matriz em uma lista de tuplas, removendo duplicatas com set e convertendo em uma matriz novamente:

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

Existem soluções existentes, para não reinventar a roda?

Para deixar claro, estou procurando:

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

BTW, eu queria usar apenas uma lista de tuplas para ele, mas as listas eram tão grandes que consumiram meu 4Gb RAM + troca de 4Gb (matrizes numpy são mais eficientes em termos de memória).

20
Sergi

Aqui está uma idéia: vai demorar um pouco de trabalho, mas pode ser bem rápido. Darei a você o caso 1d e deixarei você descobrir como estendê-lo para 2d. A função a seguir localiza os elementos exclusivos de uma matriz 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]

Agora, para estendê-lo para 2D, você precisa mudar duas coisas. Você precisará descobrir como fazer a classificação você mesmo, o importante sobre a classificação será que duas entradas idênticas terminem uma ao lado da outra. Segundo, você precisará fazer algo como (b != 0).all(axis) porque você deseja comparar a linha/coluna inteira. Deixe-me saber se isso é suficiente para você começar.

atualizado: com alguma ajuda com doug, acho que isso deve funcionar no caso 2d.

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]
17
Bi Rico

Isso deve fazer o truque:

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]))

Exemplo:

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

Meu método é transformar uma matriz 2D em uma matriz complexa 2D, onde a parte real é a 1ª coluna, a parte imaginária é a 2ª coluna. Então use np.unique. Embora isso funcione apenas com 2 colunas.

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] 

Exemplo -

a = np.array([[1, 1], [2, 3], [1, 1], [5, 4], [2, 3]])
unique2d(a)
array([[1, 1],
       [2, 3],
       [5, 4]])
5
kidnakyo

O pacote numpy_indexed (isenção de responsabilidade: sou o autor) envolve a solução postada por user545424 em uma interface agradável e testada, além de muitos recursos relacionados:

import numpy_indexed as npi
npi.unique(coordskeys)
3
Eelco Hoogendoorn
>>> 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]])
3
doug

desde que você se refere ao numpy.unique, você não se preocupa em manter a ordem original, correto? a conversão em conjunto, que remove duplicados e, em seguida, volta à lista é frequentemente usada.

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