Você pode sugerir uma função de módulo de numpy / scipy que pode encontrar máximos / mínimos locais em uma matriz numpy 1D? Obviamente, a abordagem mais simples é dar uma olhada nos vizinhos mais próximos, mas eu gostaria de ter uma solução aceita que faça parte da distro numpy.
116
Respostas:
Se você estiver procurando por todas as entradas no array 1d
a
menores do que seus vizinhos, você pode tentarVocê também pode suavizar sua matriz antes desta etapa usando
numpy.convolve()
.Não acho que haja uma função dedicada para isso.
fonte
<
por>
fornecerá os máximos locais em vez dos mínimos[False False]
Qual poderia ser o problema aqui?Em SciPy> = 0,11
Produz
Observe que esses são os índices de x que são máx. / Mín. Locais. Para obter os valores, tente:
scipy.signal
também forneceargrelmax
eargrelmin
para encontrar máximos e mínimos, respectivamente.fonte
np.random.random(12)
gera 12 valores aleatórios, eles são usados para demonstrar a funçãoargrelextrema
.test02=np.array([10,4,4,4,5,6,7,6])
, então ele não funciona. Ele não reconhece os valores consecutivos como mínimos locais.Para curvas sem muito ruído, recomendo o seguinte pequeno snippet de código:
O
+1
é importante porquediff
reduz o número do índice original.fonte
[1, 2, 2, 3, 3, 3, 2, 2, 1]
, o máximo local está obviamente em algum lugar entre os 3's no meio. Mas se você executar as funções fornecidas, obterá máximos nos índices 2,6 e mínimos nos índices 1,3,5,7, o que para mim não faz muito sentido.+1
vez denp.diff()
usarnp.gradient()
.Outra abordagem (mais palavras, menos código) que pode ajudar:
As localizações dos máximos e mínimos locais também são as localizações dos cruzamentos por zero da primeira derivada. Geralmente é muito mais fácil encontrar cruzamentos de zero do que encontrar diretamente máximos e mínimos locais.
Infelizmente, a primeira derivada tende a "amplificar" o ruído, portanto, quando um ruído significativo está presente nos dados originais, a primeira derivada é melhor usada somente depois que os dados originais tiverem algum grau de suavização aplicado.
Uma vez que a suavização é, no sentido mais simples, um filtro passa-baixa, a suavização é geralmente melhor (bem, mais facilmente) feita usando um kernel de convolução, e "modelar" esse kernel pode fornecer uma quantidade surpreendente de capacidade de preservação / aprimoramento de recursos . O processo de encontrar um kernel ideal pode ser automatizado usando uma variedade de meios, mas o melhor pode ser a força bruta simples (bastante rápido para encontrar pequenos kernels). Um bom kernel irá (como pretendido) distorcer maciçamente os dados originais, mas NÃO afetará a localização dos picos / vales de interesse.
Felizmente, muitas vezes um kernel adequado pode ser criado por meio de um SWAG simples ("suposição educada"). A largura do kernel de suavização deve ser um pouco maior do que o pico "interessante" mais largo esperado nos dados originais, e sua forma será semelhante a esse pico (uma wavelet de escala única). Para kernels que preservam a média (o que qualquer bom filtro de suavização deve ser), a soma dos elementos do kernel deve ser precisamente igual a 1,00, e o kernel deve ser simétrico em relação ao seu centro (o que significa que terá um número ímpar de elementos.
Dado um kernel de suavização ideal (ou um pequeno número de kernels otimizados para diferentes conteúdos de dados), o grau de suavização torna-se um fator de escala para (o "ganho" do) kernel de convolução.
Determinar o grau "correto" (ótimo) de suavização (ganho de kernel de convolução) pode até ser automatizado: Compare o desvio padrão dos primeiros dados derivados com o desvio padrão dos dados suavizados. Como a razão dos dois desvios padrão muda com as mudanças no grau de suavização pode ser usado para prever valores de suavização eficazes. Algumas execuções manuais de dados (que são verdadeiramente representativas) devem ser suficientes.
Todas as soluções anteriores postadas acima calculam a primeira derivada, mas não a tratam como uma medida estatística, nem as soluções acima tentam realizar a preservação / aprimoramento de recursos (para ajudar os picos sutis a "saltarem acima" do ruído).
Finalmente, a má notícia: encontrar picos "reais" torna-se uma dor de cabeça quando o ruído também tem características que parecem picos reais (largura de banda sobreposta). A próxima solução mais complexa é geralmente usar um kernel de convolução mais longo (uma "abertura de kernel mais ampla") que leva em conta a relação entre picos "reais" adjacentes (como taxas mínimas ou máximas para ocorrência de pico), ou usar vários a convolução passa usando núcleos com larguras diferentes (mas apenas se for mais rápida: é uma verdade matemática fundamental que as convoluções lineares realizadas em sequência podem sempre ser convoluídas juntas em uma única convolução). Mas geralmente é muito mais fácil primeiro encontrar uma sequência de kernels úteis (de larguras variadas) e convolvê-los juntos do que encontrar diretamente o kernel final em uma única etapa.
Esperançosamente, isso fornece informações suficientes para permitir que o Google (e talvez um bom texto de estatísticas) preencha as lacunas. Eu realmente gostaria de ter tempo para fornecer um exemplo funcional ou um link para um. Se alguém encontrar um online, poste aqui!
fonte
A partir da versão 1.1 do SciPy, você também pode usar find_peaks . Abaixo estão dois exemplos retirados da própria documentação.
Usando o
height
argumento, pode-se selecionar todos os máximos acima de um certo limite (neste exemplo, todos os máximos não negativos; isso pode ser muito útil se for necessário lidar com uma linha de base ruidosa; se você quiser encontrar os mínimos, basta multiplicar os dados de entrada por-1
):Outro argumento extremamente útil é
distance
, que define a distância mínima entre dois picos:fonte
Por que não usar a função embutida Scipy signal.find_peaks_cwt para fazer o trabalho?
resultados:
Saudações
fonte
Atualização: não fiquei feliz com o gradiente, então achei mais confiável de usar
numpy.diff
. Por favor, deixe-me saber se ele faz o que você deseja.Em relação à questão do ruído, o problema matemático é localizar máximos / mínimos. Se quisermos olhar para o ruído, podemos usar algo como convolver, que foi mencionado anteriormente.
fonte
Embora esta questão seja muito antiga. Acredito que haja uma abordagem muito mais simples no numpy (um liner).
Para encontrar um máximo ou mínimo local, queremos essencialmente encontrar quando a diferença entre os valores na lista (3-1, 9-3 ...) muda de positivo para negativo (máximo) ou negativo para positivo (mínimo). Portanto, primeiro encontramos a diferença. Então encontramos o sinal, e então encontramos as mudanças no sinal pegando a diferença novamente. (Mais ou menos como uma primeira e segunda derivadas em cálculo, só que temos dados discretos e não temos uma função contínua.)
A saída em meu exemplo não contém os extremos (o primeiro e o último valores na lista). Além disso, assim como o cálculo, se a segunda derivada for negativa, você tem o máximo e, se for positiva, você terá o mínimo.
Portanto, temos a seguinte comparação:
fonte
Nenhuma dessas soluções funcionou para mim, pois eu também queria encontrar picos no centro de valores repetidos. por exemplo, em
ar = np.array([0,1,2,2,2,1,3,3,3,2,5,0])
a resposta deve ser
Eu fiz isso usando um loop. Eu sei que não é muito limpo, mas dá conta do recado.
fonte
minm
emaxm
contêm índices de mínimos e máximos, respectivamente. Para um grande conjunto de dados, ele fornecerá muitos máximos / mínimos, então, nesse caso, suavize a curva primeiro e, em seguida, aplique este algoritmo.fonte
Outra solução usando essencialmente um operador dilate:
e para os mínimos:
Além disso,
scipy.ndimage
você pode substituirrank_filter(x, -1, size=3)
porgrey_dilation
erank_filter(x, 0, size=3)
porgrey_erosion
. Isso não requer uma classificação local, por isso é um pouco mais rápido.fonte
Outro:
fonte