找出图的峰和底并标记它们

2024-04-30 04:37:23 发布

您现在位置:Python中文网/ 问答频道 /正文

      df1
      Date           Topic  Return
      1/1/2010        A,B     -0.308648967
      1/2/2010        C,D     -0.465862046
      1/3/2010        E        0.374052392
      1/4/2010        F        0.520312204
      1/5/2010        G        0.503889198
      1/6/2010        H       -1.730646788
      1/7/2010        L,M,N    1.756295613
      1/8/2010        K        -0.598990239
      ......
      1/30/2010       z         2,124355
 Plot= df1.plot(x='Date', y='Return')

如何找到这个图的最高点和最小值,并用相应的主题标记这些特殊点?在


Tags: 标记主题datetopicreturnplotdf1最高点
2条回答

这有点取决于你对“高峰”和“低谷”的定义。通常情况下,一个人可能会关心平滑的波峰和波谷,以确定大趋势,尤其是在有噪音的情况下。如果您希望数据中的每一次细粒度的下降或上升(如果您的行是排序的),您可以使用numpy中的向量化例程进行一点欺骗。在

import numpy as np

d = np.diff(df['Return'])
i = np.argwhere((d[:-1]*d[1:])<=0).flatten()
special_points = df['Topic'][i+1]

带有np.diff()的第一行将每个返回值与下一个返回值进行比较。特别是,它会减去它们。取决于你对局部峰值/低谷的定义,它们将具有这样的特性:如果这些成对的差异在符号上交替出现,那么这些特征就是你要寻找的特征。考虑下面的峰值。在

^{pr2}$

如果你计算两两的差异,你得到一个稍短的向量

[4, -4]

注意这些符号交替出现。因此,如果你把它们相乘得到-16,它必须是负数。这正是我们的代码用来识别波峰和波谷的确切细节。降维会稍微偏移一些,所以我们将找到的索引移动1(在df['Topic'][i+1]块中)。在

注意事项:注意我们有<=而不是严格的不等式。这是为了防止我们的峰值比正常情况下更宽。考虑[1, 2, 2, 2, 2, 2, 1]。可以说,2的字符串代表一个峰值,需要捕捉。如果这不可取,那就严格规定不平等。在

另外,如果你对更宽的峰值感兴趣,这个算法仍然是不正确的。它的速度非常快,但一般来说它只计算一个波峰/波谷的超集。考虑以下几点

[1, 2, 2, 3, 2, 1]

可以说,数字3是该数据集中唯一的峰值(当然有点取决于您的定义),但是我们的算法也会提取数字2的第一个和第二个实例,因为它们位于架子上(与邻居相同)。在

额外功能:根据您对峰值的任何额外要求,scipy.signal模块有多种峰值查找算法,这些算法可能更适合您。修改此解决方案不太可能像使用适当的内置信号处理器那样快速或干净。对scipy.signal.find_peaks()的调用基本上可以复制我们在这里所做的一切,如果您需要,它有更多的选项。如果您需要任何类型的平滑或更复杂的操作,其他算法如scipy.signal.find_peaks_cwt()可能更合适。在

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Take an example data
data = {"Date":["date{i}".format(i=i) for i in range(10)], "Topic":["topic{i}".format(i=i) for i in range(10)], "Return":[1,2,3,2,1,2,4,7,1,3]}
df = pd.DataFrame.from_dict(data)

dates = np.array(df["Date"].tolist())
returns = np.array(df["Return"].tolist())

# Calculate the minimas and the maximas
minimas = (np.diff(np.sign(np.diff(returns))) > 0).nonzero()[0] + 1 
maximas = (np.diff(np.sign(np.diff(returns))) < 0).nonzero()[0] + 1

# Plot the entire data first
plt.plot(dates, returns)
# Then mark the maximas and the minimas
for minima in minimas:
    plt.plot(df.iloc[minima]["Date"], df.iloc[minima]["Return"], marker="o", label=str(df.iloc[minima]["Topic"]))
for maxima in maximas:
    plt.plot(df.iloc[maxima]["Date"], df.iloc[maxima]["Return"], marker="o", label=str(df.iloc[maxima]["Topic"]))

plt.legend()
plt.show()

示例数据帧:

^{pr2}$

它产生的绘图: enter image description here

相关问题 更多 >