首页 > 解决方案 > 如何通过在 Pandas 中使用多个列来提取时间序列中的模式?

问题描述

我有一个包含来自不同时间戳的不同度量的 DataFrame 看起来像这样:

data=np.array([["2019-08-08 08:29", 29.9, 4., 1.],["2019-08-08 08:30", 30.1, 4., 1.],["2019-08-08 08:31", 30.1, 0., 0.], ["2019-08-08 08:32", 27.2, 1., 0.], ["2019-08-08 08:33", 15.0, 2., 0.], ["2019-08-08 08:34", 15.1, 2., 0.], ["2019-08-08 08:35", 19.1, 2., 1.], ["2019-08-08 08:36", 26.7, 2., 2.], ["2019-08-08 08:37", 30.0, 2., 3.], ["2019-08-08 08:38", 30.1, 2., 3.], ["2019-08-08 08:39", 29.9, 0., 0.], ["2019-08-08 08:40", 25.1, 1., 0.], ["2019-08-08 08:41", 23.4, 2., 0.], ["2019-08-08 08:42", 15.1, 3., 0.]])

df = pd.DataFrame(data[:, 1:4], index=data[:, 0], columns=["A", "B", "C"], dtype='float64')
df.index = pd.to_datetime(df.index)
print(df.to_string())
                        A    B    C
2019-08-08 08:29:00  29.9  4.0  1.0
2019-08-08 08:30:00  30.1  4.0  1.0
2019-08-08 08:31:00  30.1  0.0  0.0
2019-08-08 08:32:00  27.2  1.0  0.0
2019-08-08 08:33:00  15.0  2.0  0.0
2019-08-08 08:34:00  15.1  2.0  0.0
2019-08-08 08:35:00  19.1  2.0  1.0
2019-08-08 08:36:00  26.7  2.0  2.0
2019-08-08 08:37:00  30.0  2.0  3.0
2019-08-08 08:38:00  30.1  2.0  3.0
2019-08-08 08:39:00  29.9  0.0  0.0
2019-08-08 08:40:00  25.1  1.0  0.0
2019-08-08 08:41:00  23.4  2.0  0.0
2019-08-08 08:42:00  15.1  3.0  0.0

我想找到定义如下的数据中的所有模式:

以下是由水平条表示的模式的值图:

plt.figure(figsize=(10, 8))
plt.subplot(211)
plt.plot(df.index, df.A)
plt.axvline(x="2019-08-08 08:31", color="red")
plt.axvline(x="2019-08-08 08:37", color='red')
plt.axvline(x="2019-08-08 08:39", color='green')
plt.subplot(212)
plt.plot(df.index, df.B)
plt.plot(df.index, df.C)
plt.axvline(x="2019-08-08 08:31", color="red")
plt.axvline(x="2019-08-08 08:37", color='red')
plt.axvline(x="2019-08-08 08:39", color='green')
plt.show()

绘制数据和模式

红色条锁定一个模式,绿色条是新模式的开始。

为了识别模式,我首先创建了两列来查找模式的开头和结尾:

df["New_pattern"] = (df['B'] == 0) & (df['B'].shift(1) != 0)
df["End_pattern"] = (df['C'] > df['C'].shift(1)) & (df['C'] == df['C'].shift(-1))

print(df.New_pattern.loc[df.New_pattern == True].to_string())
2019-08-08 08:31:00    True
2019-08-08 08:39:00    True

print(df.End_pattern.loc[df.End_pattern == True].to_string())
2019-08-08 08:37:00    True

所以这给了我很好的结果,可以在这个示例数据中找到模式的开始和结束。虽然在我的真实数据中,我的模式结束比模式开始多两倍。我认为这是因为我在两个新模式之间的 C 列的数据中有几个平坦区域,但我现在没有找到任何证据。

您还应该知道,每当测量 B 达到 0 时,测量 C 也达到 0,否则这些值不能减少,所以我知道两个新模式之间存在最大值。

我有两个问题:

  1. 如何在两个新模式时间戳之间找到结束模式,而不是使用 wole 数据框?它将通过将 true 设置为两个新模式之间第一次达到最大值的时间戳来计算。
  2. 如何使用 New_pattern 和 End_pattern 列提取数据模式?

标签: python-3.xpandasdataframetime-seriespattern-matching

解决方案


我找到了解决问题的方法,但我不知道它是否是最有效的。

我创建了一个 DataFrame,用于存储新模式开始的时间戳,并将 -1 移到另一列中。

df_pattern = df.New_pattern.loc[df.New_pattern == True].reset_index()["index"].rename("New_pattern").to_frame()
df_pattern["Next_new"] = df_pattern.shift(-1)

我通过为这个新数据帧的每一行选择新数据帧的两列的时间戳之间的所有行来计算第一个数据帧的 C 列的 idxmax。这给了我每个模式的结束。

def getEndPattern(row):
    if not pd.isnull(row[0]) and not pd.isnull(row[1]):
        return df.C.loc[row[0]:row[1]].idxmax()
    else:
        return np.nan

df_pattern["End_pattern"] = df_pattern.apply(lambda row: getEndPattern(row), axis=1)
print(df_pattern.to_string())
          New_pattern            Next_new         End_pattern
0 2019-08-08 08:31:00 2019-08-08 08:39:00 2019-08-08 08:37:00
1 2019-08-08 08:39:00                 NaT                 NaT

然后我在我的第一个 DataFrame 中创建一个由 nan 填充的列来存储当前数字的数量。我遍历包含模式时间戳的 DataFrame 的行以选择这些时间戳之间的行,然后放置正确数量的模式:

df["number_pattern"] = np.nan
for index, row in df_pattern.iterrows():
    if not pd.isnull(row[1]):
        df["number_pattern"].loc[row[0]:row[2]] = index
print(df.to_string())

                        A    B    C  New_pattern  number_pattern
2019-08-08 08:29:00  29.9  4.0  1.0        False             NaN
2019-08-08 08:30:00  30.1  4.0  1.0        False             NaN
2019-08-08 08:31:00  30.1  0.0  0.0         True             0.0
2019-08-08 08:32:00  27.2  1.0  0.0        False             0.0
2019-08-08 08:33:00  15.0  2.0  0.0        False             0.0
2019-08-08 08:34:00  15.1  2.0  0.0        False             0.0
2019-08-08 08:35:00  19.1  2.0  1.0        False             0.0
2019-08-08 08:36:00  26.7  2.0  2.0        False             0.0
2019-08-08 08:37:00  30.0  2.0  3.0        False             0.0
2019-08-08 08:38:00  30.1  2.0  3.0        False             NaN
2019-08-08 08:39:00  29.9  0.0  0.0         True             NaN
2019-08-08 08:40:00  25.1  1.0  0.0        False             NaN
2019-08-08 08:41:00  23.4  2.0  0.0        False             NaN
2019-08-08 08:42:00  15.1  3.0  0.0        False             NaN
2019-08-08 08:42:00  15.1  3.0  0.0        False             NaN
2019-08-08 08:42:00  18.1  3.0  1.0        False             NaN
2019-08-08 08:42:00  15.1  3.0  1.0        False             NaN

现在,当我想做一些分析时,我将按模式的数量进行分组,或者使用带有时间戳的 DataFrame。

这是我的解决方案,但我很乐意欢迎其他使用 Pandas 或 Python 技巧的建议,这些建议可能会让你更容易、更快或只是以不同的方式看到不同的方法。


推荐阅读