python:根据条件对时间序列数据进行分组或拆分

Posted

技术标签:

【中文标题】python:根据条件对时间序列数据进行分组或拆分【英文标题】:python: grouping or splitting up time series data based on conditions 【发布时间】:2020-06-18 19:04:21 【问题描述】:

我在工作中经常处理时间序列数据,我一直在尝试使用 python(特别是 pandas)来加快一些工作。我有一些代码可以读取DataFrame 中的数据并识别满足指定条件的段。然后,它将这些段分成单独的 DataFrame。

我在这里有一个示例DataFrame

        Date      Time  Pressure   Temp  Flow  Valve Position
0   3/5/2020  12:00:01      5.32  22.12   199            1.00
1   3/5/2020  12:00:02      5.36  22.25   115            0.95
2   3/5/2020  12:00:03      5.33  22.18   109            0.92
3   3/5/2020  12:00:04      5.38  23.51   103            0.90
4   3/5/2020  12:00:05      5.42  24.27    99            0.89
5   3/5/2020  12:00:06      5.49  25.91    92            0.85
6   3/5/2020  12:00:07      5.55  26.78    85            0.82
7   3/5/2020  12:00:08      5.61  29.88    82            0.76
8   3/5/2020  12:00:09      5.69  31.16    87            0.79
9   3/5/2020  12:00:10      5.72  32.01    97            0.87
10  3/5/2020  12:00:11      5.59  29.68   104            0.90
11  3/5/2020  12:00:12      5.53  24.55   111            0.93
12  3/5/2020  12:00:13      5.48  23.54   116            0.96
13  3/5/2020  12:00:14      5.44  23.11   119            1.00
14  3/5/2020  12:00:15      5.41  23.08   121            1.00

我编写的代码可以满足我的要求,但确实很难理解,而且我确信它会冒犯有经验的 python 用户。

这就是它的作用: 我或多或少地根据一组条件创建了一个掩码,并为掩码中的所有True 值获取索引位置。然后它使用 NumPy 的 .diff() 函数来识别索引中的不连续性。在for 循环内,它在每个已识别不连续的位置拆分掩码。一旦完成,我可以使用现在单独的索引集从我的原始DataFrame 中切出所需的数据段。请看下面的代码:

import pandas as pd
import numpy as np

df = pd.read_csv('sample_data.csv')

idx = np.where((df['Temp'] > 23) & (df['Temp'] < 30))[0]
discontinuity = np.where(np.diff(idx) > 1)[0]
intervals = 

for i in range(len(discontinuity)+1):
    if i == 0:
        intervals[i] = df.iloc[idx[0]:idx[discontinuity[i]],1]
        if len(intervals[i].values) < 1:
            del intervals[i]
    elif i == len(discontinuity):
        intervals[i] = df.iloc[idx[discontinuity[i-1]+1]:idx[-1],1]
        if len(intervals[i].values) < 1:
            del intervals[i]
    else:
        intervals[i] = df.iloc[idx[discontinuity[i-1]+1]:idx[discontinuity[i]],1] 
        if len(intervals[i].values) < 1:
            del intervals[i]


df1 = df.loc[intervals[0].index, :]
df2 = df.loc[intervals[1].index, :]

df1df2包含原始DataFrame中对应'Temp'在23到30之间的时间(行)的所有数据。

df1:

       Date      Time  Pressure   Temp  Flow  Valve Position
3  3/5/2020  12:00:04      5.38  23.51   103            0.90
4  3/5/2020  12:00:05      5.42  24.27    99            0.89
5  3/5/2020  12:00:06      5.49  25.91    92            0.85
6  3/5/2020  12:00:07      5.55  26.78    85            0.82

df2:

        Date      Time  Pressure   Temp  Flow  Valve Position
10  3/5/2020  12:00:11      5.59  29.68   104            0.90
11  3/5/2020  12:00:12      5.53  24.55   111            0.93
12  3/5/2020  12:00:13      5.48  23.54   116            0.96
13  3/5/2020  12:00:14      5.44  23.11   119            1.00

我很高兴我能够让它为我工作,我可以忍受使用这种方法丢失的几行,但我知道这是一种非常平庸的方法,我不禁想到有人没有一个 Python 初学者可以更干净、更高效地做同样的事情。

来自 itertools 或 pandas 的 groupby 可以为此工作吗?我一直无法找到一种方法来完成这项工作。

【问题讨论】:

你介意发布 df1 和 df2 的输出 同样在您分享的示例数据集中,temp 列中没有一个值满足 idx 中的要求 - 没有一个大于 23 @sammywemmy 我添加了两个输出 dfs。该条件应该在原始表中找到满足临时条件的两块数据 【参考方案1】:

欢迎来到 Stack Overflow。

我认为你的代码可以这样简化:

# Get the subset that fulfills your conditions

df_conditioned = df.query('Temp > 23 and Temp < 30').copy()
# Check for discontinuities by looking at the indices
# I created a new column called 'Group' to keep track of the continuous indices

indices = df_conditioned.index.to_series()
df_conditioned['Group'] = ((indices - indices.shift(1)) != 1).cumsum()
# Store the groups (segments with same group number) as individual frames in a list

df_list = []
for group in df_conditioned['Group'].unique():
    df_list.append(df_conditioned.query('Group == @group').drop(columns='Group'))

希望对你有帮助!

【讨论】:

哇,这太简单了。我之前没有遇到过query@group 对我来说也是新的,在这种情况下它仍然是装饰器吗?我假设您是如何告诉query 小写“组”是for 循环迭代器而不是列标题,对吗?我唯一关心的是通过将数据从原始DataFrame 复制到df_conditioned 可以使用的内存量。我有时会在具有 1 hz 数据天数的非常大的文件上运行此代码,您认为将该副本作为中间文件会有问题吗? 你是对的,@group 是循环迭代器。它不是 python 装饰器,只是为query 编写语法的方式。当您基于简单表达式提取列时,query 很有用。实际上,由于您可以一次加载原始数据帧而不会出现内存问题,如果您不需要不符合温度查询条件的剩余数据帧,则可以在第一次查询df = df.query('Temp &gt; 23 and Temp &lt; 30) 期间覆盖原始数据帧。 @Toukenize 你能更详细地解释你做了什么吗?也许有一些循序渐进的例子?优秀的代码!

以上是关于python:根据条件对时间序列数据进行分组或拆分的主要内容,如果未能解决你的问题,请参考以下文章

python pandas groupby分组后的数据怎么用

python数据分析之Dataframe分组(group by)

如何根据数据框中的值有条件地对数据进行分组?

Python pandas数据框根据条件分组

SQL根据开始和结束时间对满足条件的时间序列进行分组

C# 属性列表。需要根据2个条件对它们进行分组[重复]