首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >找到一个数组中的峰,另一个数组中的谷值,然后以交替的方式将它们连接起来,有什么有效的方法?

找到一个数组中的峰,另一个数组中的谷值,然后以交替的方式将它们连接起来,有什么有效的方法?
EN

Stack Overflow用户
提问于 2020-06-22 22:54:42
回答 1查看 303关注 0票数 0

我有两个数组,波峰和波谷,我想找到波峰和波谷,然后以交替的方式将它们连接起来,这样就不会有两个或更多的波峰/波谷连续出现,例如:

代码语言:javascript
复制
Highs = [107165., 107095., 107000., 107045., 106980., 106940., 106890.,
         106740., 106565., 106615., 106375., 106440., 106445., 106290.,
         106245., 106270., 106075., 105990., 106260., 106395., 106315.,
         106080., 106180., 106305., 106265., 106180., 106360., 106260.,
         106110., 106070.]

Lows = [106815., 106845., 106905., 106920., 106850., 106850., 106565.,
        106460., 106380., 106305., 106250., 106280., 106155., 106035.,
        106055., 105960., 105915., 105875., 105760., 106110., 105945.,
        105820., 105865., 106095., 106020., 105925., 106045., 106020.,
        105925., 105880.]

应用高斯滤波器来平滑数据

代码语言:javascript
复制
from scipy.ndimage.filters import gaussian_filter1d
gauH = gaussian_filter1d(Highs, 1)
gauL = gaussian_filter1d(Lows, 1)

在高峰和低谷中寻找高峰

代码语言:javascript
复制
iCeils  = (np.diff(np.sign(np.diff(gauH))) < 0).nonzero()[0] + 1 # Ceils index 
iFloors = (np.diff(np.sign(np.diff(gauL))) > 0).nonzero()[0] + 1 # Floors index

现在我需要对它们进行连接和排序,找出一行中有多个峰/谷,并从数组中删除低位/高位。目前我是这样做的:

将1赋值给山峰,将0赋值给山谷

代码语言:javascript
复制
iCeils = np.concatenate([np.reshape(iCeils, (len(iCeils), 1)), np.reshape(np.ones(len(iCeils)), 
(len(iCeils), 1))], axis = 1).astype(int)

iFloors = np.concatenate([np.reshape(iFloors, (len(iFloors), 1)), np.reshape(np.zeros(len(iFloors)), 
(len(iFloors), 1))], axis = 1).astype(int)

在pandas数据帧中连接两者并进行排序

代码语言:javascript
复制
iCF = pd.DataFrame(np.concatenate([iCeils, iFloors], axis = 0), columns = ['Val', 'kind']).sort_values(['Val'])

对于上下文,它给出了类似这样的东西:

代码语言:javascript
复制
iCF = pd.DataFrame([[17,  0],
                    [19,  1],
                    [21,  0],
                    [25,  0],
                    [26,  1]], columns = ['Val', 'kind'])

一行中有2个谷,值分别为21和25,Low21 = 105820 < Low25 = 105925,因此从dataframe中删除25,并获得以下结果:

代码语言:javascript
复制
iCF = pd.DataFrame([[17,  0],
                    [19,  1],
                    [21,  0],
                    [26,  1]], columns = ['Val', 'kind'])

现在我可以遍历整个数据帧,检查列'kind‘是否连续具有相同的值,并删除最高的谷和最低的峰值,但我不确定循环是否会更有效,有什么建议吗?

Edit1,为了更清楚,我想去掉蓝色圆圈中的圆点

Edit2,我打错了哪个Val应该被移除

EN

回答 1

Stack Overflow用户

发布于 2020-06-23 00:20:02

下面是另一种方法,先使用scipy.signal,然后进行列表理解。

编辑:用整个数据集(25466行)替换测试数据。整个代码每个循环需要3.67秒±364毫秒(平均值±标准。dev.共运行7次,每个循环1次)在我的机器上运行,包括所有导入和绘图。

代码语言:javascript
复制
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.signal import find_peaks
from collections import Counter

dataset=pd.read_csv('/path/to/WIN205.csv', delimiter = ':', header = 0)

Highs=np.array(dataset.High)

Lows=np.array(dataset.Low)

#find peaks by simple comparison of neighboring value
peaks, _ = find_peaks(Highs)
plt.plot(Highs,color='gray', zorder=1)

#invert Lows to transform
Lows_inv=Lows*(-1)
valleys, _ = find_peaks(Lows_inv)

#plot the results
plt.figure()
plt.subplot(121)
plt.plot(Highs,color='gray', zorder=1)
plt.scatter(peaks, Highs[peaks], color='red', marker='x', s=100, zorder=2)
plt.title('Peaks',fontsize=18)
plt.xlabel('Values (n°)',fontsize=15)
plt.ylabel('Highs (?)',fontsize=15)
plt.subplot(122)
plt.plot(Lows,color='gray', zorder=1)
plt.scatter(valleys, Lows[valleys], color='red', marker='x', s=100, zorder=2)
plt.title('Valleys',fontsize=18)
plt.xlabel('Values (n°)',fontsize=15)
plt.ylabel('Lows (?)',fontsize=15)

#combine peaks and valleys
df_peaks=pd.DataFrame({'category':np.ones(len(peaks)), 'height': Highs[peaks]},index=peaks)
df_valleys=pd.DataFrame({'category':np.zeros(len(valleys)), 'height': Lows[valleys]}, index=valleys)
df_pv=pd.concat([df_peaks,df_valleys], sort=True).sort_index()

#split df by blocks of consecutive same categories 
df_pv['block'] = (df_pv.category.shift(1) != df_pv.category).astype(int).cumsum()

#count number of values in each block
blocks=Counter(df_pv['block'])

def filter_outputs(block_id, nb_vals):
    
    #work on blocks with consecutive same categories
    if nb_vals>1:
        
        df_block=df_pv[df_pv.block==block_id]
        
        #check if peak or valley block and keep max if peak, min if valley
        if df_block.category.iloc[0]==1:
            indxs_to_keep=[np.where(df_pv.height==np.nanmax(df_block.height))[0][0]]
        else:
            indxs_to_keep=[np.where(df_pv.height==np.nanmin(df_block.height))[0][0]]
    
    #keep other blocks unchanged
    else:
        
        indxs_to_keep=[np.where(df_pv.block==block_id)[0]]
            
    return indxs_to_keep

#find all indexes to keep
indxs_to_keep=[filter_outputs(block_id, nb_vals) for block_id, nb_vals in blocks.items()]

#and keep them!
df_pv_filtered=df_pv.reset_index().iloc[[val for sublist in indxs_to_keep for val in sublist]]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62517288

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档