1D numpy 배열에서 로컬 최대 값 / 최소값을 찾을 수있는 numpy / scipy의 모듈 함수를 제안 할 수 있습니까? 분명히 가장 간단한 접근 방식은 가장 가까운 이웃을 보는 것입니다. 그러나 저는 numpy 배포판의 일부인 수용된 솔루션을 갖고 싶습니다.
1D numpy 배열에서 로컬 최대 값 / 최소값을 찾을 수있는 numpy / scipy의 모듈 함수를 제안 할 수 있습니까? 분명히 가장 간단한 접근 방식은 가장 가까운 이웃을 보는 것입니다. 그러나 저는 numpy 배포판의 일부인 수용된 솔루션을 갖고 싶습니다.
답변:
a
이웃보다 작은 1d 배열의 모든 항목을 찾고 있다면 시도해 볼 수 있습니다.
numpy.r_[True, a[1:] < a[:-1]] & numpy.r_[a[:-1] < a[1:], True]
당신은 또한 수 부드럽게 사용이 단계 전에 배열을 numpy.convolve()
.
나는 이것에 대한 전용 기능이 없다고 생각합니다.
<
함께 >
당신에게 대신 최소값의 로컬 최대 줄 것이다
[False False]
이 있습니다. 여기서 문제 는 무엇일까요?
SciPy에서> = 0.11
import numpy as np
from scipy.signal import argrelextrema
x = np.random.random(12)
# for local maxima
argrelextrema(x, np.greater)
# for local minima
argrelextrema(x, np.less)
생산
>>> x
array([ 0.56660112, 0.76309473, 0.69597908, 0.38260156, 0.24346445,
0.56021785, 0.24109326, 0.41884061, 0.35461957, 0.54398472,
0.59572658, 0.92377974])
>>> argrelextrema(x, np.greater)
(array([1, 5, 7]),)
>>> argrelextrema(x, np.less)
(array([4, 6, 8]),)
이것은 로컬 최대 / 최소 인 x의 인덱스입니다. 값을 얻으려면 다음을 시도하십시오.
>>> x[argrelextrema(x, np.greater)[0]]
scipy.signal
또한 제공 argrelmax
하고 argrelmin
각각 최대 값과 최소값을 찾기위한.
np.random.random(12)
12 개의 임의의 값을 생성하며 함수를 설명하는 데 사용됩니다 argrelextrema
.
test02=np.array([10,4,4,4,5,6,7,6])
이면 작동하지 않습니다. 연속 된 값을 로컬 최소값으로 인식하지 않습니다.
노이즈가 많지 않은 곡선의 경우 다음과 같은 작은 코드 스 니펫을 권장합니다.
from numpy import *
# example data with some peaks:
x = linspace(0,4,1e3)
data = .2*sin(10*x)+ exp(-abs(2-x)**2)
# that's the line, you need:
a = diff(sign(diff(data))).nonzero()[0] + 1 # local min+max
b = (diff(sign(diff(data))) > 0).nonzero()[0] + 1 # local min
c = (diff(sign(diff(data))) < 0).nonzero()[0] + 1 # local max
# graphical output...
from pylab import *
plot(x,data)
plot(x[b], data[b], "o", label="min")
plot(x[c], data[c], "o", label="max")
legend()
show()
이 +1
있기 때문에 중요하다 diff
원래의 인덱스 수를 줄일 수 있습니다.
[1, 2, 2, 3, 3, 3, 2, 2, 1]
로컬 최대 값은 분명히 중간의 3 사이 어딘가에 있습니다. 그러나 제공 한 함수를 실행하면 인덱스 2,6에서 최대 값을 얻고 인덱스 1,3,5,7에서 최소값을 얻습니다.
+1
대신에 np.diff()
사용 np.gradient()
.
도움이 될 수있는 또 다른 접근 방식 (더 많은 단어, 적은 코드) :
국소 최댓값과 최솟값의 위치는 1 차 미분의 제로 교차점의 위치이기도합니다. 일반적으로 로컬 최대 값과 최소값을 직접 찾는 것보다 제로 교차점을 찾는 것이 훨씬 쉽습니다.
불행히도 1 차 미분은 노이즈를 "증폭"하는 경향이 있으므로 원본 데이터에 상당한 노이즈가있는 경우 1 차 미분은 원본 데이터에 어느 정도의 평활화가 적용된 후에 만 사용하는 것이 가장 좋습니다.
평활화는 가장 단순한 의미에서 저역 통과 필터이기 때문에 평활화는 종종 컨볼 루션 커널을 사용하여 가장 잘 (가장 쉽게) 수행되며 커널이 놀라운 양의 기능 보존 / 향상 기능을 제공 할 수 있도록 "형성"합니다. . 최적의 커널을 찾는 프로세스는 다양한 수단을 사용하여 자동화 할 수 있지만 가장 좋은 방법은 단순한 무차별 대입 (작은 커널을 찾는 데 매우 빠름) 일 수 있습니다. 좋은 커널은 (의도 한대로) 원본 데이터를 크게 왜곡하지만 관심있는 피크 / 밸리의 위치에는 영향을주지 않습니다.
다행히도 간단한 SWAG ( "교육 된 추측")를 통해 적절한 커널을 만들 수 있습니다. 평활화 커널의 너비는 원래 데이터에서 예상되는 가장 넓은 "흥미로운"피크보다 약간 더 넓어야하며 그 모양은 해당 피크 (단일 스케일 웨이블릿)와 유사합니다. 평균 보존 커널 (좋은 평활 필터가 있어야하는 것)의 경우 커널 요소의 합은 정확히 1.00이어야하며 커널은 중심에 대해 대칭이어야합니다 (즉, 요소 수가 홀수임을 의미합니다.
최적의 평활화 커널 (또는 다른 데이터 콘텐츠에 최적화 된 적은 수의 커널)이 주어지면 평활화 정도는 컨볼 루션 커널 (의 "이득")에 대한 스케일링 인자가됩니다.
평활화 (컨볼 루션 커널 이득)의 "올바른"(최적) 정도를 결정하는 것도 자동화 할 수 있습니다. 1 차 도함수 데이터의 표준 편차를 평활 데이터의 표준 편차와 비교합니다. 스무딩 캠 정도의 변화에 따라 두 표준 편차의 비율이 어떻게 변하는지를 사용하여 효과적인 스무딩 값을 예측합니다. 몇 가지 수동 데이터 실행 (정말로 대표적 임) 만 있으면됩니다.
위에 게시 된 모든 이전 솔루션은 1 차 도함수를 계산하지만이를 통계적 측정으로 취급하지 않으며, 위의 솔루션은 기능 유지 / 향상 평활화를 수행하려고 시도하지 않습니다 (미묘한 피크가 노이즈 "위로"도약하는 데 도움이 됨).
마지막으로, 나쁜 소식 : "실제"피크를 찾는 것은 노이즈가 실제 피크 (중복 대역폭)처럼 보이는 기능도 포함 할 때 왕실의 고통이됩니다. 다음으로 더 복잡한 솔루션은 일반적으로 인접한 "실제"피크 (예 : 피크 발생에 대한 최소 또는 최대 속도) 간의 관계를 고려하는 더 긴 컨볼 루션 커널 ( "더 넓은 커널 애 퍼처")을 사용하거나 다중을 사용하는 것입니다. 컨볼 루션은 너비가 다른 커널을 사용하여 전달됩니다 (그러나 더 빠를 경우에만 : 순차적으로 수행되는 선형 컨볼 루션이 항상 단일 컨볼 루션으로 함께 컨볼 루션 될 수 있다는 것이 기본적인 수학적 사실입니다). 그러나 한 단계에서 최종 커널을 직접 찾는 것보다 먼저 유용한 커널 시퀀스 (다양한 너비)를 찾아서 함께 연결하는 것이 훨씬 쉽습니다.
이 정보가 Google (그리고 아마도 좋은 통계 텍스트)이 공백을 메울 수 있도록 충분한 정보를 제공하기를 바랍니다. 작업 한 예제 나 링크를 제공 할 시간이 있었으면합니다. 누군가가 온라인에서 하나를 발견하면 여기에 게시하십시오!
SciPy 버전 1.1부터 find_peaks 를 사용할 수도 있습니다 . 다음은 문서 자체에서 가져온 두 가지 예입니다.
height
인수를 사용하면 특정 임계 값 이상의 모든 최대 값을 선택할 수 있습니다 (이 예에서는 모두 음이 아닌 최대 값입니다. 잡음이있는 기준선을 처리해야하는 경우 매우 유용 할 수 있습니다. 최소값을 찾으려면 입력 값을 곱하면됩니다. 작성자 -1
:) :
import matplotlib.pyplot as plt
from scipy.misc import electrocardiogram
from scipy.signal import find_peaks
import numpy as np
x = electrocardiogram()[2000:4000]
peaks, _ = find_peaks(x, height=0)
plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.plot(np.zeros_like(x), "--", color="gray")
plt.show()
또 다른 매우 유용한 인수는 distance
두 봉우리 사이의 최소 거리를 정의하는입니다.
peaks, _ = find_peaks(x, distance=150)
# difference between peaks is >= 150
print(np.diff(peaks))
# prints [186 180 177 171 177 169 167 164 158 162 172]
plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.show()
Scipy 내장 함수 signal.find_peaks_cwt 를 사용하여 작업을 수행하지 않는 이유는 무엇 입니까?
from scipy import signal
import numpy as np
#generate junk data (numpy 1D arr)
xs = np.arange(0, np.pi, 0.05)
data = np.sin(xs)
# maxima : use builtin function to find (max) peaks
max_peakind = signal.find_peaks_cwt(data, np.arange(1,10))
# inverse (in order to find minima)
inv_data = 1/data
# minima : use builtin function fo find (min) peaks (use inversed data)
min_peakind = signal.find_peaks_cwt(inv_data, np.arange(1,10))
#show results
print "maxima", data[max_peakind]
print "minima", data[min_peakind]
결과 :
maxima [ 0.9995736]
minima [ 0.09146464]
문안 인사
업데이트 :
그래디언트가 마음에 들지 않아 사용하는 것이 더 안정적이라는 것을 알았습니다 numpy.diff
. 원하는대로 작동하는지 알려주세요.
노이즈 문제와 관련하여 수학적 문제는 앞서 언급 한 convolve와 같은 것을 사용할 수있는 노이즈를보고 싶다면 최대 / 최소를 찾는 것입니다.
import numpy as np
from matplotlib import pyplot
a=np.array([10.3,2,0.9,4,5,6,7,34,2,5,25,3,-26,-20,-29],dtype=np.float)
gradients=np.diff(a)
print gradients
maxima_num=0
minima_num=0
max_locations=[]
min_locations=[]
count=0
for i in gradients[:-1]:
count+=1
if ((cmp(i,0)>0) & (cmp(gradients[count],0)<0) & (i != gradients[count])):
maxima_num+=1
max_locations.append(count)
if ((cmp(i,0)<0) & (cmp(gradients[count],0)>0) & (i != gradients[count])):
minima_num+=1
min_locations.append(count)
turning_points = {'maxima_number':maxima_num,'minima_number':minima_num,'maxima_locations':max_locations,'minima_locations':min_locations}
print turning_points
pyplot.plot(a)
pyplot.show()
이 질문은 정말 오래되었습니다. numpy (1 라이너)에는 훨씬 더 간단한 접근 방식이 있다고 생각합니다.
import numpy as np
list = [1,3,9,5,2,5,6,9,7]
np.diff(np.sign(np.diff(list))) #the one liner
#output
array([ 0, -2, 0, 2, 0, 0, -2])
로컬 최대 값 또는 최소값을 찾으려면 목록 (3-1, 9-3 ...)의 값 간의 차이가 양수에서 음수 (최대) 또는 음수에서 양수 (최소)로 변경되는 시점을 본질적으로 찾고 싶습니다. 따라서 먼저 차이점을 찾습니다. 그런 다음 기호를 찾은 다음 다시 차이를 가져옴으로써 기호의 변화를 찾습니다. (미적분학의 1 차 및 2 차 도함수처럼, 우리는 이산 데이터를 가지고 있고 연속 함수가 없습니다.)
내 예제의 출력에는 극값 (목록의 첫 번째 및 마지막 값)이 포함되어 있지 않습니다. 또한 미적분과 마찬가지로 2 차 도함수가 음수이면 최대 값이고 양수이면 최소값입니다.
따라서 다음과 같은 매치업이 있습니다.
[1, 3, 9, 5, 2, 5, 6, 9, 7]
[0, -2, 0, 2, 0, 0, -2]
Max Min Max
반복되는 값의 중심에서도 피크를 찾고 싶었 기 때문에 이러한 솔루션 중 어느 것도 저에게 효과적이지 않았습니다. 예를 들어
ar = np.array([0,1,2,2,2,1,3,3,3,2,5,0])
대답은
array([ 3, 7, 10], dtype=int64)
나는 루프를 사용하여 이것을했다. 나는 그것이 매우 깨끗하지 않다는 것을 알고 있지만 작업을 완료합니다.
def findLocalMaxima(ar):
# find local maxima of array, including centers of repeating elements
maxInd = np.zeros_like(ar)
peakVar = -np.inf
i = -1
while i < len(ar)-1:
#for i in range(len(ar)):
i += 1
if peakVar < ar[i]:
peakVar = ar[i]
for j in range(i,len(ar)):
if peakVar < ar[j]:
break
elif peakVar == ar[j]:
continue
elif peakVar > ar[j]:
peakInd = i + np.floor(abs(i-j)/2)
maxInd[peakInd.astype(int)] = 1
i = j
break
peakVar = ar[i]
maxInd = np.where(maxInd)[0]
return maxInd
import numpy as np
x=np.array([6,3,5,2,1,4,9,7,8])
y=np.array([2,1,3,5,3,9,8,10,7])
sortId=np.argsort(x)
x=x[sortId]
y=y[sortId]
minm = np.array([])
maxm = np.array([])
i = 0
while i < length-1:
if i < length - 1:
while i < length-1 and y[i+1] >= y[i]:
i+=1
if i != 0 and i < length-1:
maxm = np.append(maxm,i)
i+=1
if i < length - 1:
while i < length-1 and y[i+1] <= y[i]:
i+=1
if i < length-1:
minm = np.append(minm,i)
i+=1
print minm
print maxm
minm
및 maxm
각각 최소값과 최대 값의 인덱스를 포함한다. 거대한 데이터 세트의 경우 많은 최대 / 최소값을 제공하므로이 경우 먼저 곡선을 매끄럽게 만든 다음이 알고리즘을 적용합니다.
기본적으로 확장 연산자를 사용하는 또 다른 솔루션 :
import numpy as np
from scipy.ndimage import rank_filter
def find_local_maxima(x):
x_dilate = rank_filter(x, -1, size=3)
return x_dilate == x
최소값 :
def find_local_minima(x):
x_erode = rank_filter(x, -0, size=3)
return x_erode == x
또한,에서 scipy.ndimage
당신을 대체 할 수있는 rank_filter(x, -1, size=3)
과 grey_dilation
와 rank_filter(x, 0, size=3)
함께 grey_erosion
. 로컬 정렬이 필요하지 않으므로 약간 더 빠릅니다.
다른 것:
def local_maxima_mask(vec):
"""
Get a mask of all points in vec which are local maxima
:param vec: A real-valued vector
:return: A boolean mask of the same size where True elements correspond to maxima.
"""
mask = np.zeros(vec.shape, dtype=np.bool)
greater_than_the_last = np.diff(vec)>0 # N-1
mask[1:] = greater_than_the_last
mask[:-1] &= ~greater_than_the_last
return mask