我正在使用pandas.Series.Rolling.apply功能中的scipy函数Find_Peaks寻求帮助。我抛出TypeError:每次尝试都只能将size-1数组转换为Python标量,我不明白1.)为什么2.)如何正确编写
我的最终目标:从透视日期开始,找到信号中的历史峰值。
find_peaks函数根据峰值属性识别信号内的峰值。我正在使用Mathworks-> prominence methodology
中的突出方法有用的示例该函数本身采用一维数组,并返回一个元组(peaks:ndarray,properties:dict)。
所需的输出:
x = np.ones((12,))
x[3] = 10
x[7] = 10
x[11] = 10
x = pd.Series(x)
x.rolling(4).apply(lambda x: find_peaks(x,prominence=.2)[0])
0 []
1 []
2 []
3 [3]
4 [3]
5 [3]
6 [3]
7 [3,7]
8 [3,7]
9 [3,7]
10 [3,7]
11 [3,7]
dtype: float64
尝试/错误消息:
x.rolling(4).apply(lambda x: find_peaks(x,prominence=.2)[0])
TypeError:只有大小为1的数组可以转换为Python标量
from SO36680402发生此错误当函数期望单个值但您传递一个数组时,引发错误“仅将length-1数组可以转换为Python标量”。
但是,SO45254174在以下示例中似乎与此TypeError相矛盾:
import numpy as np
import pandas as pd
n = 3
a = np.arange(5)
df = pd.DataFrame(a, columns=['a'])
def keep(window, windows):
windows.append(window.copy())
return window[-1]
windows = list()
df['a'].rolling(n).apply(keep, args=(windows,))
df = df.tail(n)
df['a_window'] = windows
它将数组/向量添加到每个滚动块,从而产生:
a a_window
2 2 [0.0, 1.0, 2.0]
3 3 [1.0, 2.0, 3.0]
4 4 [2.0, 3.0, 4.0]
第一次尝试:
x.rolling(4).apply(lambda x: find_peaks(x,prominence=.2)[0])
错误:TypeError:只能将大小为1的数组转换为Python标量
第二次尝试:
def _find_peaks(array,prominence=.2):
peaks,_ = find_peaks(array,prominence=prominence)
return np.empty((0,0)) if peaks.shape[0]==0 else peaks
x.rolling(4).apply(_find_peaks)
TypeError:只有大小为1的数组可以转换为Python标量
任何有关如何编写以及为什么抛出错误的想法都将不胜感激!
答案 0 :(得分:1)
您可以做的是改为使用数组,并在find_peaks
中使用wlen
参数来设置窗口长度,而不要使用pd.rolling
:
wlen:整数或浮点数,可选:样本中的窗口长度,可以选择将每个峰的评估面积限制为x的子集。峰值始终位于窗口的中间,因此给定的长度将四舍五入到下一个奇数整数。此参数可以加快计算速度
因此,您可以执行以下操作:
find_peaks(x.values, prominence=0.2, wlen=4)
(array([3, 7], dtype=int64),
{'left_bases': array([2, 6], dtype=int64),
'prominences': array([9., 9.]),
'right_bases': array([4, 8], dtype=int64)})
答案 1 :(得分:0)
谢谢尼克松的想法。实际上,我真的很喜欢使用“突出显示”选项来定义峰。我找到了两个解决问题的方法,它们的格式与我期望的输出格式不完全相同。
这是我想出的。解决方案1的显示速度更快,但是对我来说,解决方案2的阅读起来更容易。
解决方案1 :As_Strided Rolling Window
numpy的as_strided函数可以非常快速地创建滚动窗口。
import numpy as np
import pandas as pd
from numpy.lib import stride_tricks
from scipy.signal import find_peaks
x = np.ones((12,))
x[3] = 10
x[7] = 10
x[11] = 10
frames_example_1 = pd.DataFrame(stride_tricks.as_strided(x,shape=(len(x)-7+1,7),strides=(8,8)))
peaks = frames_example_1.apply(find_peaks,axis=1,prominence=0.2).apply(lambda x: x[0])
aligned_peaks = np.arange(1,7).reshape(6,1) + \
pd.DataFrame(peaks.tolist(),index=np.arange(6,12),columns=['first_peak','second_peak'])
aligned_peaks.index.name = 'perspective date'
解决方案2 :Numpy Fancy Indexing Fancy Indexing Explained 仍然利用numpy,因为我无法找到一种通过熊猫完成原始代码的方法。
window = 7
frames, frame_length = len(x) - window +1, window
indexer = np.tile(np.arange(frame_length),frames).reshape(frames,frame_length) + \
np.arange(frames).reshape(frames,1)
peaks = pd.DataFrame(x[indexer],index=np.arange(6,12)).apply(find_peaks,axis=1,prominence=0.2).apply(lambda x: x[0])
然后执行与之前相同的步骤:
aligned_peaks = np.arange(1,7).reshape(6,1) + pd.DataFrame(peaks.tolist(),index=np.arange(6,12),columns=['first_peak','second_peak'])
aligned_peaks.index.name = 'perspective date'