Preciso encontrar linhas exclusivas em um arquivo numpy.array
.
Por exemplo:
>>> a # I have
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
>>> new_a # I want to get to
array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 1, 1, 0]])
Eu sei que posso criar um conjunto e um loop sobre a matriz, mas estou procurando uma numpy
solução pura e eficiente . Acredito que existe uma maneira de definir o tipo de dados como nulo e então eu poderia apenas usá-lo numpy.unique
, mas não consegui descobrir como fazê-lo funcionar.
Respostas:
A partir do NumPy 1.13, pode-se simplesmente escolher o eixo para a seleção de valores únicos em qualquer matriz N-dim. Para obter linhas exclusivas, é possível:
unique_rows = np.unique(original_array, axis=0)
fonte
np.unique(list_cor, axis=0)
fornece a matriz com linhas duplicadas removidas ; ele não filtra a matriz para elementos exclusivos na matriz original . Veja aqui , por exemplo ..original_array.sort(axis=1)
Mais uma solução possível
fonte
np.vstack(list({tuple(row) for row in AIPbiased[i, :, :]}))
FutureWarning: as matrizes para empilhar devem ser passadas como um tipo de "sequência", como lista ou tupla. O suporte para iteráveis sem sequência, como geradores, está obsoleto no NumPy 1.16 e gera um erro no futuro.Outra opção para o uso de matrizes estruturadas é usar uma exibição de um
void
tipo que une toda a linha em um único item:EDIT Adicionado
np.ascontiguousarray
após a recomendação de @ seberg. Isso reduzirá a velocidade do método se a matriz ainda não estiver contígua.EDITAR A descrição acima pode ser levemente acelerada, talvez à custa da clareza, fazendo:
Além disso, pelo menos no meu sistema, em termos de desempenho, é par ou melhor que o método lexsort:
fonte
b = a.view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))
:?np.void
tipo de dados do tamanho do número de bytes em uma linha completa. São duas semelhantes ao que você obtém se tiver uma matriz de senp.uint8
a visualizar comonp.uint16
s, que combina a cada duas colunas em uma única, mas mais flexível.np.ascontiguousarray
ou similar para ser geralmente seguro (eu sei que é um pouco mais restritivo do que o necessário, mas ...). As linhas devem ser contíguas para que a exibição funcione conforme o esperado.np.unique
em uma matriz denp.void
retornos, um erro relacionado ao mergesort não está sendo implementado para esse tipo. Mas funciona bem em 1.7.-0.
não será comparada como igual a+0.
, enquanto uma comparação elemento a elemento teria-0.==+0.
(conforme especificado pelo padrão ieee float). Veja stackoverflow.com/questions/26782038/…Se você deseja evitar o gasto de memória com a conversão para uma série de tuplas ou outra estrutura de dados semelhante, pode explorar as matrizes estruturadas do numpy.
O truque é exibir sua matriz original como uma matriz estruturada, em que cada item corresponde a uma linha da matriz original. Isso não faz uma cópia e é bastante eficiente.
Como um exemplo rápido:
Para entender o que está acontecendo, dê uma olhada nos resultados intermediários.
Depois que visualizamos as coisas como uma matriz estruturada, cada elemento da matriz é uma linha na sua matriz original. (Basicamente, é uma estrutura de dados semelhante a uma lista de tuplas.)
Uma vez executado
numpy.unique
, obteremos uma matriz estruturada de volta:Que precisamos ver como uma matriz "normal" (
_
armazena o resultado do último cálculoipython
, e é por isso que você está vendo_.view...
):E, em seguida, remodelar novamente em uma matriz 2D (
-1
é um espaço reservado que indica ao numpy para calcular o número correto de linhas, forneça o número de colunas):Obviamente, se você quiser ser mais conciso, pode escrever como:
O que resulta em:
fonte
lexsort
. Eu pensei que você estava se referindo ao uso de uma lista de tuplas. Sim,lexsort
provavelmente é a melhor opção neste caso. Eu tinha esquecido, e pulei para uma solução excessivamente complexa.np.unique
quando eu o executonp.random.random(100).reshape(10,10)
retorna todos os elementos individuais exclusivos, mas você deseja as linhas exclusivas; primeiro, você precisa colocá-las em tuplas:Essa é a única maneira que vejo você alterando os tipos para fazer o que deseja, e não tenho certeza se a iteração da lista a ser alterada para tuplas está de acordo com o seu "não repetir"
fonte
< 100
linhas por invocação. Isso descreve precisamente como é executado o desempenho de linhas únicas.uniques
contém elementos exclusivos. Potencialmente, eu entendi mal a forma esperada dearray
- você poderia ser mais preciso aqui?uniques
é classificada (e, portanto, diferente das linhasarray
).B = np.array([[1,2],[2,1]]); A = np.unique([tuple(row) for row in B]); print(A) = array([[1, 2],[1, 2]])
O np.unique funciona classificando uma matriz nivelada e, em seguida, verificando se cada item é igual ao anterior. Isso pode ser feito manualmente, sem achatar:
Este método não usa tuplas e deve ser muito mais rápido e mais simples do que outros métodos fornecidos aqui.
NOTA: Uma versão anterior disso não tinha o ind logo após a [, o que significa que os índices incorretos foram usados. Joe Kington também argumenta que isso faz várias cópias intermediárias. O método a seguir economiza menos, fazendo uma cópia classificada e, em seguida, usando visualizações:
Isso é mais rápido e usa menos memória.
Além disso, se você deseja encontrar linhas exclusivas em um ndarray, independentemente de quantas dimensões estão na matriz, o seguinte funcionará:
Uma questão interessante restante seria se você quisesse classificar / único ao longo de um eixo arbitrário de uma matriz de dimensões arbitrárias, algo que seria mais difícil.
Editar:
Para demonstrar as diferenças de velocidade, executei alguns testes no ipython dos três métodos diferentes descritos nas respostas. Com o seu a exato, não há muita diferença, embora esta versão seja um pouco mais rápida:
Com um a maior, no entanto, essa versão acaba sendo muito, muito mais rápida:
fonte
a[ind[1:]]
é uma cópia, etc.) Por outro lado, sua solução geralmente é 2-3 vezes mais rápida que a minha até você ficar sem memória RAM.dtype
nos seus horários? Eu acho que você entendeu errado. No meu sistema, chamarnp.unique
como descrito na minha resposta é um pouco mais rápido do que usar um dos seus dois saboresnp.lexsort
. E é cerca de 5x mais rápido se a matriz para encontrar itens únicos tiver forma(10000, 100)
. Mesmo se você decidir reimplementar o quenp.unique
faz para reduzir algum tempo (menor) de execução, o recolhimento de cada linha em um único objeto executa comparações mais rápidas do que ter que recorrernp.any
à comparação das colunas, especialmente para contagens mais altas de colunas.dtype
é justoa.dtype
, ou seja, o tipo de dados que está sendo visualizado, como foi feito por Joe Kington em sua resposta. Se houver muitas colunas, outra maneira (imperfeita!) De manter as coisas rápidas usandolexsort
é classificar apenas algumas colunas. Isso é específico dos dados, pois é necessário saber quais colunas fornecem variação suficiente para classificar perfeitamente. Por exemploa.shape = (60000, 500)
- uma espécie nas 3 primeiras colunas:ind = np.lexsort((a[:, 2], a[:, 1], a[:, 0]))
. A economia de tempo é bastante substancial, mas o aviso de isenção de novo: pode não pegar todos os casos - depende dos dados.Aqui está outra variação da resposta pitônica @Greg
fonte
Comparei a alternativa sugerida para a velocidade e descobri que, surpreendentemente, a
unique
solução de exibição nula é até um pouco mais rápida que a nativa de numpyunique
com oaxis
argumento. Se você está procurando velocidade, vai quererCódigo para reproduzir o gráfico:
fonte
vstack_dict
:, nunca usa um ditado, chaves entre dentes é uma compreensão definida e, portanto, seu comportamento é quase idêntico avstatck_set
. Comovstack_dict
falta linha de desempenho para o gráfico, parece que ela está apenas sendo coberta pelovstack_set
gráfico de desempenho, uma vez que são muito semelhantes!vstack
variante.Não gostei de nenhuma dessas respostas, porque nenhuma lida com matrizes de ponto flutuante em um sentido de álgebra linear ou espaço vetorial, onde duas linhas sendo "iguais" significam "dentro de alguns 𝜀". A única resposta que tem um limite de tolerância, https://stackoverflow.com/a/26867764/500207 , considerou o limite de precisão tanto em elementos quanto em decimal , o que funciona em alguns casos, mas não é matematicamente geral como um verdadeira distância do vetor.
Aqui está a minha versão:
A função de domínio público acima é usada
scipy.spatial.distance.pdist
para encontrar a distância euclidiana (personalizável) entre cada par de linhas. Em seguida, ele compara cada distância a umathresh
antiga para encontrar as linhas que estão uma dentrothresh
da outra e retorna apenas uma linha de cadathresh
cluster.Como sugerido, a distância
metric
não precisa ser euclidiana -pdist
pode calcular diversas distâncias, incluindocityblock
(norma de Manhattan) ecosine
(o ângulo entre vetores).Se
thresh=0
(o padrão), as linhas precisam ser exatas para serem consideradas "únicas". Outros bons valores parathresh
uso de precisão de máquina em escala, ou sejathresh=np.spacing(1)*1e3
,.fonte
set
) como representante de cadathresh
bairro de tamanho, a função pode permitir que o usuário especificar como escolher esse ponto, por exemplo, usar o “médio” ou o ponto mais próximo do centróide, etc.thresh
cluster seria aleatória por causa da natureza desordenada deset
. É claro que é um brainfart da minha parte, asset
lojas tuplas de índices que estão nothresh
-neighborhood, então issofindRows
faz de fato retorno, para cadathresh
-cluster, a primeira linha na mesma.Por que não usar
drop_duplicates
de pandas:fonte
O pacote numpy_indexed (exoneração de responsabilidade: eu sou seu autor) envolve a solução postada por Jaime em uma interface agradável e testada, além de muitos outros recursos:
fonte
O np.unique trabalha com uma lista de tuplas:
Com uma lista de listas, gera uma
TypeError: unhashable type: 'list'
fonte
Com base na resposta desta página, escrevi uma função que replica a capacidade da
unique(input,'rows')
função do MATLAB , com o recurso adicional de aceitar tolerância para verificar a exclusividade. Ele também retorna os índices tais quec = data[ia,:]
edata = c[ic,:]
. Informe se você vê alguma discrepância ou erro.fonte
Além da excelente resposta do @Jaime, outra maneira de reduzir uma linha é usar
a.strides[0]
(supondo quea
seja C-contíguo) que seja igual aa.dtype.itemsize*a.shape[0]
. Além disso,void(n)
é um atalho paradtype((void,n))
. chegamos finalmente a esta versão mais curta:Para
fonte
Para fins gerais, como matrizes aninhadas multidimensionais em 3D ou superiores, tente o seguinte:
o que satisfaz o seu conjunto de dados 2D:
dá:
Mas também matrizes 3D como:
dá:
fonte
unique
return_index
Jaime como deve fazer essa últimareturn
linha mais simples. Apenas indexe o originalar
no eixo direito.Nenhuma dessas respostas funcionou para mim. Estou assumindo que minhas linhas únicas continham strings e não números. No entanto, esta resposta de outro segmento funcionou:
Fonte: https://stackoverflow.com/a/38461043/5402386
Você pode usar os métodos da lista .count () e .index ()
fonte
Na verdade, podemos transformar mxn numpy array numpy em mx 1 numpy string array, tente usar a seguinte função, que fornece count , inverse_idx e etc, assim como numpy.unique:
Exemplo:
fonte
Vamos obter a matriz numpy inteira como uma lista, soltar duplicados dessa lista e finalmente retornar nossa lista exclusiva de volta para uma matriz numpy:
fonte
A solução mais direta é transformar as linhas em um único item, transformando-as em seqüências de caracteres. Cada linha pode ser comparada como um todo por sua exclusividade usando numpy. Essa solução é generalizada, você só precisa remodelar e transpor sua matriz para outras combinações. Aqui está a solução para o problema fornecido.
Darei:
Envie meu prêmio nobel pelo correio
fonte
fonte