如何简化类正弦波数据的波峰波谷提取与箱线图绘制流程?
简化类正弦波峰谷波动分析的代码流程
问题背景
我正在分析类正弦波形式的温度时序数据波动,目前已有可行方案,但代码流程太繁琐:需要分别创建波峰、波谷的DataFrame,再和主数据合并,最后生成差值序列绘制箱线图。我想知道是否必须创建这两个DataFrame?这类简单操作的代码量实在没必要这么大。
我的核心需求是对比随时间变化的温度波动,后续还要实现不同时段(比如2021年12月与2022年12月)的数据对比。以下是我用Scipy心电数据做的示例(模拟温度数据):
原冗余代码
import pandas as pd from scipy.datasets import electrocardiogram from scipy.signal import find_peaks from scipy import ndimage # 加载并预处理数据 temp = electrocardiogram()[200:300] temp = ndimage.gaussian_filter1d(temp, 2) # 修正原代码笔误:x改为temp peaks, _ = find_peaks(temp) troughs, _ = find_peaks(-temp) # 创建波谷、波峰的DataFrame troughs_df = pd.DataFrame() troughs_df.index = troughs troughs_df['troughs'] = 'trough' peaks_df = pd.DataFrame() peaks_df.index = peaks peaks_df['peaks'] = 'peak' # 合并主数据与峰谷DataFrame temp_series = pd.Series(temp, name='temp') temp = pd.merge(temp_series, troughs_df, left_index=True, right_index=True, how='outer') temp = pd.merge(temp, peaks_df, left_index=True, right_index=True, how='outer') # 标记峰谷并计算差值画箱线图 temp['peaks and troughs'] = temp[['peaks', 'troughs']].fillna('').sum(axis=1) temp.query("`peaks and troughs` != ''")['temp'].diff().plot.box()
输入数据(Scipy心电切片)
array([ 0.125, 0.16 , 0.165, 0.17 , 0.185, 0.22 , 0.225, 0.235, 0.22 , 0.23 , 0.25 , 0.28 , 0.27 , 0.25 , 0.255, 0.245, 0.235, 0.235, 0.25 , 0.23 , 0.245, 0.23 , 0.22 , 0.215, 0.18 , 0.12 , 0.075, 0.065, 0.06 , 0.055, 0.025, -0.005, -0.04 , -0.085, -0.135, -0.145, -0.14 , -0.12 , -0.12 , -0.16 , -0.195, -0.2 , -0.215, -0.2 , -0.2 , -0.215, -0.255, -0.27 , -0.225, -0.225, -0.24 , -0.25 , -0.23 , -0.19 , -0.18 , -0.2 , -0.21 , -0.215, -0.21 , -0.21 , -0.205, -0.225, -0.23 , -0.24 , -0.245, -0.23 , -0.23 , -0.21 , -0.2 , -0.185, -0.175, -0.175, -0.19 , -0.19 , -0.19 , -0.2 , -0.175, -0.13 , -0.09 , -0.095, -0.13 , -0.17 , -0.16 , -0.135, -0.1 , -0.09 , -0.115, -0.115, -0.08 , -0.04 , -0.065, -0.105, -0.12 , -0.12 , -0.11 , -0.105, -0.11 , -0.15 , -0.155, -0.16 ])
原代码输出的峰谷标记结果
temp troughs peaks peaks and troughs 13 0.3000 NaN peak peak 48 -0.2000 trough NaN trough 56 -0.2000 NaN peak peak 63 -0.2000 trough NaN trough 89 -0.1000 NaN peak peak
简化方案:无需创建额外DataFrame
完全不需要单独创建峰谷的DataFrame,直接合并峰谷的索引,提取对应的值后计算差值即可,代码量大幅减少:
简化后的代码
import pandas as pd from scipy.datasets import electrocardiogram from scipy.signal import find_peaks from scipy import ndimage # 数据加载与预处理 temp = electrocardiogram()[200:300] temp = ndimage.gaussian_filter1d(temp, 2) peaks, _ = find_peaks(temp) troughs, _ = find_peaks(-temp) # 合并峰谷索引并排序,提取对应值 all_extrema_indices = sorted(list(peaks) + list(troughs)) extrema_values = pd.Series(temp[all_extrema_indices], index=all_extrema_indices, name='temp') # 计算差值并绘制箱线图 extrema_values.diff().dropna().plot.box()
简化说明
- 跳过冗余DataFrame创建:直接把峰谷索引合并后排序,用NumPy索引直接提取对应的数据点,无需多次merge操作。
- 逻辑更直接:核心需求是获取峰谷的差值,不需要额外标记"peak"/"trough"(如果后续需要标记,也可以用一行代码完成,完全不需要单独建DataFrame)。
- 兼容后续时段对比:如果要对比不同时段的数据,只需对每个时段重复上述简化流程,再把多个差值序列合并后绘制箱线图即可,代码结构依然简洁。
简化代码的核心输出
和原代码一致,最终会生成相同的箱线图:
内容的提问来源于stack exchange,提问作者Cam
相关产品推荐
相关产品推荐

