Python / SciPy를위한 피크 찾기 알고리즘


136

첫 번째 파생물이나 다른 것의 제로 크로싱을 찾아서 직접 쓸 수는 있지만 표준 라이브러리에 포함되는 공통 기능이있는 것 같습니다. 누구나 하나를 알고 있습니까?

내 특정 응용 프로그램은 2D 배열이지만 일반적으로 FFT 등에서 피크를 찾는 데 사용됩니다.

특히 이러한 종류의 문제에는 여러 개의 강한 피크가 있으며 무시해야 할 노이즈로 인해 발생하는 더 작은 "피크"가 많이 있습니다. 이것들은 단지 예일뿐입니다. 내 실제 데이터가 아닙니다.

1 차원 피크 :

피크가있는 FFT 출력

2 차원 피크 :

원형 피크의 라돈 변환 출력

피크 찾기 알고리즘은 이러한 피크의 위치 (값뿐만 아니라)를 찾고, 2 차 보간법 등을 사용하여 최대 값을 갖는 인덱스 만이 아니라 실제 샘플 간 피크를 찾는 것이 이상적입니다 .

일반적으로 몇 개의 강한 피크에만 관심이 있기 때문에 특정 임계 값을 초과하거나 진폭에 따라 순위가 매겨진 순서 목록 의 첫 번째 n 피크 이기 때문에 선택 됩니다.

내가 말했듯이, 나는 이와 같은 것을 쓰는 법을 알고있다. 잘 작동하는 것으로 알려진 기존 기능이나 패키지가 있는지 묻고 있습니다.

최신 정보:

나는 매트랩 스크립트를 번역 하며 1-D의 경우에 친절하게 작동하지만, 더 좋을 수 있습니다.

업데이트 된 업데이트 :

sixtenbe 1D 사례를위한 더 나은 버전만들었습니다 .


@endolith 파이썬으로 번역 한 원본 MATLAB 파일이 있습니까? 감사!
Spacey



1
@endolith 나는이 질문이 꽤 오래되었다는 것을 알고 있지만 꽤 유용하다;) 오늘 아침에 몇 시간을 보냈 find_peaks으므로 나중에 참조 할 때 유용 할 수있는 이 대답 을 추가 했습니다 . (당신은 이미 2009 년부터 이것을 발견했다고 확신하지만, 몇 년 안에 다시 질문을 할 때 다른 사람들 + 나 자신을위한 것입니다!)
Basj

답변:


74

scipy.signal.find_peaks이름에서 알 수 있듯이 함수 가이 기능에 유용합니다. 그러나 잘 매개 변수를 이해하는 것이 중요하다 width, threshold,distance 그리고 무엇보다도prominence 좋은 피크 추출을 얻을 수 있습니다.

내 테스트와 문서에 따르면 저명한 개념은 좋은 피크를 유지하고 시끄러운 피크를 버리는 "유용한 개념"입니다.

(토포 그래피) 눈에 띄는 것은 무엇입니까 ? 그것은이다 "필요한 최소한의 높이가 어느 높은 지형 정상 회담에서 얻을 하강" 가 여기 볼 수 있듯이, :

여기에 이미지 설명을 입력하십시오

아이디어는 다음과 같습니다.

중요도가 높을수록 피크가 더 "중요"합니다.

테스트:

여기에 이미지 설명을 입력하십시오

나는 많은 어려움을 보이기 때문에 (잡음) 주파수가 변하는 정현파를 의도적으로 사용했습니다. 우리는 볼 수 width는 최소로 설정 한 경우 때문에 매개 변수가 여기에 매우 유용하지 않습니다 width너무 높은, 그때는 고주파 부분에 매우 가까운 피크를 추적 할 수 없습니다. width너무 낮게 설정 하면 신호 왼쪽에 원하지 않는 피크가 많이 생깁니다. 와 같은 문제입니다 distance.threshold직접 이웃과 비교할 때 여기에서는 유용하지 않습니다. prominence최고의 솔루션을 제공하는 솔루션입니다. 이러한 많은 매개 변수를 결합 할 수 있습니다!

암호:

import numpy as np
import matplotlib.pyplot as plt 
from scipy.signal import find_peaks

x = np.sin(2*np.pi*(2**np.linspace(2,10,1000))*np.arange(1000)/48000) + np.random.normal(0, 1, 1000) * 0.15
peaks, _ = find_peaks(x, distance=20)
peaks2, _ = find_peaks(x, prominence=1)      # BEST!
peaks3, _ = find_peaks(x, width=20)
peaks4, _ = find_peaks(x, threshold=0.4)     # Required vertical distance to its direct neighbouring samples, pretty useless
plt.subplot(2, 2, 1)
plt.plot(peaks, x[peaks], "xr"); plt.plot(x); plt.legend(['distance'])
plt.subplot(2, 2, 2)
plt.plot(peaks2, x[peaks2], "ob"); plt.plot(x); plt.legend(['prominence'])
plt.subplot(2, 2, 3)
plt.plot(peaks3, x[peaks3], "vg"); plt.plot(x); plt.legend(['width'])
plt.subplot(2, 2, 4)
plt.plot(peaks4, x[peaks4], "xk"); plt.plot(x); plt.legend(['threshold'])
plt.show()

이것이 내가 추구하는 것입니다. 그러나 2D 배열에서 두드러진 구현을 알고 있습니까?
Jason

43

나는 비슷한 문제를보고 있는데, 가장 좋은 참고 문헌 중 일부는 화학에서 나온 것입니다 (질량 사양 데이터의 피크에서). 피킹 알고리즘에 대한 철저한 검토를 위해 이것을 읽으십시오 . 이것은 내가 찾은 최고 발견 기술에 대한 가장 명확한 리뷰 중 하나입니다. (잡음은 잡음이 많은 데이터에서 이러한 종류의 피크를 찾는 데 가장 좋습니다.).

피크가 명확하게 정의되어 있고 노이즈에 숨겨져 있지 않은 것 같습니다. 필자는 부드러운 savtizky-golay 파생 상품을 사용하여 피크를 찾는 것이 좋습니다 (위의 데이터를 구별하면 위양성이 엉망이됩니다). 이것은 매우 효과적인 기술이며 구현하기가 매우 쉽습니다 (기본 작업과 함께 매트릭스 클래스가 필요함). 단순히 첫 번째 SG 파생 상품의 제로 크로싱을 찾으면 행복 할 것입니다.


2
나는 특정 이미지에서만 작동하는 것이 아니라 범용 솔루션을 찾고있었습니다. MATLAB 스크립트를 Python에 적용했으며 제대로 작동합니다.
endolith 2009

1
바로 Matlab은 알고리즘의 좋은 소스입니다. 스크립트는 어떤 기술을 사용합니까? (BTW, SG는 매우 일반적인 목적의 기술입니다).
Paul

2
위에 연결했습니다. 기본적으로 이웃의 특정 임계 값보다 큰 로컬 최대 값 만 검색합니다. 더 좋은 방법이 있습니다.
endolith 2009

1
@Paul 나는 그 페이지를 북마크했다. IYO와 요약하면이 피크 피킹 비즈니스에 가장 적합한 기술은 무엇입니까?
Spacey

왜 세 점 중 중간이 다른 두 점보다 크거나 작은 경우 테스트보다 제로 미분 제로가 더 좋은 이유는 무엇입니까? 나는 이미 sg transfor를 적용했으며 추가 비용 인 것 같습니다.
kirill_igum 1

20

scipy scipy.signal.find_peaks_cwt에는 귀하의 요구에 적합한 것 같은 기능이 있지만, 경험이 없으므로 권장 할 수 없습니다.

http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.find_peaks_cwt.html


12
그래, 내가 이것을 물었을 때 그것은 존재하지 않았다. 그리고 나는 그것을 어떻게 사용하는지 아직도 모르겠다
endolith

1
얼마 전에 이것을 추가했지만 훌륭하게 작동했습니다. 파이처럼 사용하는 것이 간단합니다. 배열과 원하는 피크의 모든 너비를 나열하는 다른 배열 (예 : np.arange (1,10))을 전달하십시오. 필요한 경우 마른 또는 넓은 피크를 필터링하는 것이 좋습니다. 다시 감사합니다!
Miles

15

파이썬에서 어떤 피크 찾기 알고리즘을 사용해야하는지 잘 모르는 사용자를 위해 대안에 대한 빠른 개요가 있습니다. https://github.com/MonsieurV/py-findpeaks

MatLab findpeaks함수 와 동등한 기능원한다면 Marcos Duarte 의 detect_peaks 함수 가 좋은 선택 이라는 것을 알았습니다 .

사용하기 매우 쉽습니다.

import numpy as np
from vector import vector, plot_peaks
from libs import detect_peaks
print('Detect peaks with minimum height and distance filters.')
indexes = detect_peaks.detect_peaks(vector, mph=7, mpd=2)
print('Peaks are: %s' % (indexes))

어느 것이 당신에게 줄 것입니까?

detect_peaks 결과


1
이 게시물이 작성되었으므로 find_peaks기능이에 추가되었습니다 scipy.
onewhaleid

6

신뢰할 수있는 방식으로 스펙트럼에서 피크를 감지하는 것은 예를 들어 80 년대 음악 / 오디오 신호에 대한 정현파 모델링에 대한 모든 작업과 같이 꽤 많이 연구되었습니다. 문헌에서 "Sinusoidal Modeling"을 찾으십시오.

신호가 예제와 같이 깨끗하다면 간단한 "N 이웃보다 진폭이 큰 것을 알려주십시오"는 합리적으로 잘 작동합니다. 시끄러운 신호가있는 경우 간단하지만 효과적인 방법은 피크를 제 시간에보고 추적하는 것입니다. 그런 다음 스펙트럼 피크 대신 스펙트럼 선을 감지합니다. IOW, 신호의 슬라이딩 윈도우에서 FFT를 계산하여 일련의 스펙트럼을 스펙트로 그램이라고도합니다. 그런 다음 시간에 따라 (즉, 연속 창에서) 스펙트럼 피크의 진화를 살펴 봅니다.


정점을 보시겠습니까? 스펙트럼 라인을 감지 하시겠습니까? 이것이 무엇을 의미하는지 잘 모르겠습니다. 구형파에 적합합니까?
endolith

아, 당신은 FFT 대신 STFT를 사용하는 것에 대해 이야기하고 있습니다. 이 질문은 구체적으로 FFT에 관한 것이 아닙니다. 그것은 단지 예일뿐입니다. 일반적인 1D 또는 2D 배열에서 피크를 찾는 것입니다.
endolith

4

나는 당신이 찾고있는 것이 SciPy가 제공한다고 생각하지 않습니다. 이 상황에서 코드를 직접 작성합니다.

scipy.interpolate의 스플라인 보간 및 스무딩은 매우 훌륭하며 피크를 피팅 한 다음 최대 위치를 찾는 데 매우 도움이 될 수 있습니다.


16
사과하지만 이것이 답변이 아니라 의견이어야한다고 생각합니다. 유용 할 수있는 기능에 대한 모호한 제안과 함께 스스로 작성하는 것을 제안합니다 (바울의 대답에있는 기능은 우연히 더 관련성이 있습니다).
Ami Tavory

1

데이터에 대한 특이 치를 찾는 표준 통계 함수 및 방법이 있으며, 아마도 첫 번째 경우에 필요할 것입니다. 파생 상품을 사용하면 두 번째 문제가 해결됩니다. 그러나 연속 함수와 샘플링 된 데이터를 모두 해결하는 방법은 확실하지 않습니다.


0

우선, 추가 사양이 없으면 "피크"의 정의가 모호합니다. 예를 들어, 다음 시리즈의 경우 5-4-5를 1 피크 또는 2로 호출 하시겠습니까?

1-2-1-2-1-1-5-4-5-1-1-5-1

이 경우 최소한 두 개의 임계 값이 필요합니다. 1) 최고 값을 피크로 등록 할 수있는 위의 높은 임계 값; 그리고 2) 임계 값이 낮으므로 작은 값으로 분리 된 극단 값은 두 개의 피크가됩니다.

피크 검출은 "극단 값의 설명"으로도 알려진 극단 값 이론 문헌에서 잘 연구 된 주제입니다. 일반적인 응용 분야에는 환경 변수의 연속 판독을 기반으로 위험 이벤트를 식별하는 것 (예 : 폭풍 이벤트를 감지하기 위해 풍속 분석)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.