dada uma matriz de números inteiros como
[1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5]
Eu preciso mascarar elementos que se repetem mais que N
vezes. Para esclarecer: o objetivo principal é recuperar a matriz de máscaras booleanas e usá-la posteriormente para cálculos de classificação.
Eu vim com uma solução bastante complicada
import numpy as np
bins = np.array([1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5])
N = 3
splits = np.split(bins, np.where(np.diff(bins) != 0)[0]+1)
mask = []
for s in splits:
if s.shape[0] <= N:
mask.append(np.ones(s.shape[0]).astype(np.bool_))
else:
mask.append(np.append(np.ones(N), np.zeros(s.shape[0]-N)).astype(np.bool_))
mask = np.concatenate(mask)
dando por exemplo
bins[mask]
Out[90]: array([1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5])
Existe uma maneira melhor de fazer isso?
EDIT, # 2
Muito obrigado pelas respostas! Aqui está uma versão reduzida do gráfico de benchmark do MSeifert. Obrigado por me indicar simple_benchmark
. Mostrando apenas as 4 opções mais rápidas:
Conclusão
A idéia proposta por Florian H , modificada por Paul Panzer, parece ser uma ótima maneira de resolver esse problema, pois é bem simples e direto numpy
. numba
No entanto, se você estiver bem em usar , a solução do MSeifert supera a outra.
Optei por aceitar a resposta do MSeifert como solução, pois é a resposta mais geral: lida corretamente com matrizes arbitrárias com blocos (não exclusivos) de elementos repetidos consecutivos. Caso numba
não seja possível, a resposta de Divakar também vale a pena dar uma olhada!
Respostas:
Quero apresentar uma solução usando o numba que deve ser bastante fácil de entender. Presumo que você deseja "mascarar" itens repetidos consecutivos:
Por exemplo:
Atuação:
Usando
simple_benchmark
- no entanto, não incluí todas as abordagens. É uma escala de log-log:Parece que a solução numba não consegue superar a solução de Paul Panzer, que parece um pouco mais rápida para grandes matrizes (e não requer uma dependência adicional).
No entanto, ambos parecem ter um desempenho superior às outras soluções, mas retornam uma máscara em vez da matriz "filtrada".
fonte
out
argumento (ou talvez da forma funcional do operador), então não pude salvar essa cópia. Btw eu gosto bastantesimple_benchmark
.simple_benchmark
! obrigado por isso e, claro, pela resposta. Como também estou usandonumba
para outras coisas, estou propenso a usá-lo aqui e fazer dessa a solução. entre uma rocha e um lugar duro lá ...Isenção de responsabilidade: esta é apenas uma implementação mais sólida da ideia de @ FlorianH:
Para matrizes maiores, isso faz uma enorme diferença:
fonte
[1,1,1,1,2,2,1,1,2,2]
.Abordagem 1: aqui está uma maneira vetorizada -
Amostra de execução -
Abordagem 2: versão um pouco mais compacta -
Abordagem # 3: Usando as contagens agrupadas e
np.repeat
(embora não nos dê a máscara) -Abordagem # 4: com um
view-based
método -Abordagem 5: com um
view-based
método sem índices deflatnonzero
-fonte
Você poderia fazer isso com a indexação. Para qualquer N, o código seria:
resultado:
fonte
timeit
execuções.Uma maneira muito mais agradável seria usar
numpy
ounique()
função . Você receberá entradas exclusivas em sua matriz e também a contagem de quantas vezes elas aparecem:resultado:
fonte
Você pode usar um loop while que verifica se o elemento N da matriz está posicionado de volta é igual ao atual. Observe que esta solução assume que a matriz está ordenada.
fonte
len(question)
paralen(bins)
Você poderia usar grouby agrupar os elementos comuns e lista de filtros que são mais de N .
fonte
Solução
Você poderia usar
numpy.unique
. A variávelfinal_mask
pode ser usada para extrair os elementos traget da matrizbins
.Saída :
fonte
bins
, certo?final_values
diretamente, você pode descomentar a linha só comentou na solução e, nesse caso, você pode descartar três linhas:mask = ...
,final_mask = ...
ebins[final_mask]
.