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, :]
df1
和df2
包含原始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 > 23 and Temp < 30)
期间覆盖原始数据帧。
@Toukenize 你能更详细地解释你做了什么吗?也许有一些循序渐进的例子?优秀的代码!以上是关于python:根据条件对时间序列数据进行分组或拆分的主要内容,如果未能解决你的问题,请参考以下文章
python pandas groupby分组后的数据怎么用