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!