熊猫测量自条件以来经过的时间
Posted
技术标签:
【中文标题】熊猫测量自条件以来经过的时间【英文标题】:Pandas measure elapsed time since a condition 【发布时间】:2019-05-08 11:21:26 【问题描述】:我有以下数据框:
Time Work
2018-12-01 10:00:00 Off
2018-12-01 10:00:02 On
2018-12-01 10:00:05 On
2018-12-01 10:00:06 On
2018-12-01 10:00:07 On
2018-12-01 10:00:09 Off
2018-12-01 10:00:11 Off
2018-12-01 10:00:14 On
2018-12-01 10:00:16 On
2018-12-01 10:00:18 On
2018-12-01 10:00:20 Off
我想创建一个新列,其中包含设备开始工作以来经过的时间。
Time Work Elapsed Time
2018-12-01 10:00:00 Off 0
2018-12-01 10:00:02 On 2
2018-12-01 10:00:05 On 5
2018-12-01 10:00:06 On 6
2018-12-01 10:00:07 On 7
2018-12-01 10:00:09 Off 0
2018-12-01 10:00:11 Off 0
2018-12-01 10:00:14 On 3
2018-12-01 10:00:16 On 5
2018-12-01 10:00:18 On 7
2018-12-01 10:00:20 Off 0
我该怎么做?
【问题讨论】:
欢迎来到 Stack Overflow,Rafael!我来这里肯定只是因为标题看起来很有趣,但离开学习 Pandas 在这种情况下的实际含义。 【参考方案1】:你可以使用groupby
:
# df['Time'] = pd.to_datetime(df['Time'], errors='coerce') # Uncomment if needed.
sec = df['Time'].dt.second
df['Elapsed Time'] = (
sec - sec.groupby(df.Work.eq('Off').cumsum()).transform('first'))
df
Time Work Elapsed Time
0 2018-12-01 10:00:00 Off 0
1 2018-12-01 10:00:02 On 2
2 2018-12-01 10:00:05 On 5
3 2018-12-01 10:00:06 On 6
4 2018-12-01 10:00:07 On 7
5 2018-12-01 10:00:09 Off 0
6 2018-12-01 10:00:11 Off 0
7 2018-12-01 10:00:14 On 3
8 2018-12-01 10:00:16 On 5
9 2018-12-01 10:00:18 On 7
10 2018-12-01 10:00:20 Off 0
这个想法是提取秒部分并从状态从“关闭”变为“开启”的第一时刻减去经过的时间。这是使用transform
和first
完成的。
cumsum
用于标识组:
df.Work.eq('Off').cumsum()
0 1
1 1
2 1
3 1
4 1
5 2
6 3
7 3
8 3
9 3
10 4
Name: Work, dtype: int64
如果您的设备有可能在“开启”状态下持续数分钟,则将 sec
初始化为:
sec = df['Time'].values.astype(np.int64) // 10e8
df['Elapsed Time'] = (
sec - sec.groupby(df.Work.eq('Off').cumsum()).transform('first'))
df
Time Work Elapsed Time
0 2018-12-01 10:00:00 Off 0.0
1 2018-12-01 10:00:02 On 2.0
2 2018-12-01 10:00:05 On 5.0
3 2018-12-01 10:00:06 On 6.0
4 2018-12-01 10:00:07 On 7.0
5 2018-12-01 10:00:09 Off 0.0
6 2018-12-01 10:00:11 Off 0.0
7 2018-12-01 10:00:14 On 3.0
8 2018-12-01 10:00:16 On 5.0
9 2018-12-01 10:00:18 On 7.0
10 2018-12-01 10:00:20 Off 0.0
【讨论】:
@Rafael 是的,这里的假设是您的行以“关闭”条件开始。您可以在框架的开头附加一行吗? @Rafael 好的,关于你的第二点,df['Time'].values.astype(np.int64) // 10e8
有效吗?
代码运行良好几秒钟。但是,当 Work 列的第一个单元格为“On”时,经过的时间不是从零开始的。此外,当时间更改为下一分钟时,经过的时间为负数。我尝试使用 sec = df['Time'].astype(int) 但出现错误:cannot astype a datetimelike from [datetime64[ns]] to [int32];
@Rafael 你能再读一遍我的 cmets 吗?
我删除了评论并再次发布,以便我可以编辑它。关于您的答案,我每天都会收到数据,它从“开”开始到“开”结束,所以我不确定是否可以追加一行,但我会尝试使用日期更改作为条件。代码 df['Time'].values.astype(np.int64) // 10e8 确实有效。【参考方案2】:
IIUC first
和 transform
(df.Time-df.Time.groupby(df.Work.eq('Off').cumsum()).transform('first')).dt.seconds
Out[1090]:
0 0
1 2
2 5
3 6
4 7
5 0
6 0
7 3
8 5
9 7
10 0
Name: Time, dtype: int64
【讨论】:
如果我将时间列设置为索引,我应该如何更改代码以便它也可以工作? @Rafael df.reset_index(inplace=True) 我在您为已用时间编写的代码之前添加了 df.set_index('Time', inplace=True) 行。所以我必须调整代码以在索引列而不是时间列中减去。我试过 (df.index-df.index.groupby(df.Operation.eq('Off').cumsum()).transform('first')) 但没有用。 @Rafael 这是df.reset_index(inplace=True)
重置未设置【参考方案3】:
您可以使用两个groupbys
。第一个计算每个组内的时间差。第二个然后将每个组中的那些相加。
s = (df.Work=='Off').cumsum()
df['Elapsed Time'] = df.groupby(s).Time.diff().dt.total_seconds().fillna(0).groupby(s).cumsum()
输出
Time Work Elapsed Time
0 2018-12-01 10:00:00 Off 0.0
1 2018-12-01 10:00:02 On 2.0
2 2018-12-01 10:00:05 On 5.0
3 2018-12-01 10:00:06 On 6.0
4 2018-12-01 10:00:07 On 7.0
5 2018-12-01 10:00:09 Off 0.0
6 2018-12-01 10:00:11 Off 0.0
7 2018-12-01 10:00:14 On 3.0
8 2018-12-01 10:00:16 On 5.0
9 2018-12-01 10:00:18 On 7.0
10 2018-12-01 10:00:20 Off 0.0
【讨论】:
代码运行良好。但是,当数据帧的第一个工作单元为“开启”时,经过的时间不为零。 @Rafael 好点。可能有一种巧妙的方法可以在计算中修复它,但您可以在事后使用df.loc[df.index < s[s==1].idxmax(), 'Elapsed Time'] = 0
修复它。我想如果机器从不启动仍然存在问题,但这也可以修复或处理。【参考方案4】:
使用 groupby,您可以这样做:
df['Elapsed Time'] = (df.groupby(df.Work.eq('Off').cumsum()).Time
.transform(lambda x: x.diff()
.dt.total_seconds()
.cumsum())
.fillna(0))
>>> df
Time Work Elapsed Time
0 2018-12-01 10:00:00 Off 0.0
1 2018-12-01 10:00:02 On 2.0
2 2018-12-01 10:00:05 On 5.0
3 2018-12-01 10:00:06 On 6.0
4 2018-12-01 10:00:07 On 7.0
5 2018-12-01 10:00:09 Off 0.0
6 2018-12-01 10:00:11 Off 0.0
7 2018-12-01 10:00:14 On 3.0
8 2018-12-01 10:00:16 On 5.0
9 2018-12-01 10:00:18 On 7.0
10 2018-12-01 10:00:20 Off 0.0
【讨论】:
【参考方案5】:一种 numpy slicy 方法
u, f, i = np.unique(df.Work.eq('Off').values.cumsum(), True, True)
t = df.Time.values
df['Elapsed Time'] = t - t[f[i]]
df
Time Work Elapsed Time
0 2018-12-01 10:00:00 Off 00:00:00
1 2018-12-01 10:00:02 On 00:00:02
2 2018-12-01 10:00:05 On 00:00:05
3 2018-12-01 10:00:06 On 00:00:06
4 2018-12-01 10:00:07 On 00:00:07
5 2018-12-01 10:00:09 Off 00:00:00
6 2018-12-01 10:00:11 Off 00:00:00
7 2018-12-01 10:00:14 On 00:00:03
8 2018-12-01 10:00:16 On 00:00:05
9 2018-12-01 10:00:18 On 00:00:07
10 2018-12-01 10:00:20 Off 00:00:00
我们可以确定整数位
df['Elapsed Time'] = (t - t[f[i]]).astype('timedelta64[s]').astype(int)
df
Time Work Elapsed Time
0 2018-12-01 10:00:00 Off 0
1 2018-12-01 10:00:02 On 2
2 2018-12-01 10:00:05 On 5
3 2018-12-01 10:00:06 On 6
4 2018-12-01 10:00:07 On 7
5 2018-12-01 10:00:09 Off 0
6 2018-12-01 10:00:11 Off 0
7 2018-12-01 10:00:14 On 3
8 2018-12-01 10:00:16 On 5
9 2018-12-01 10:00:18 On 7
10 2018-12-01 10:00:20 Off 0
【讨论】:
以上是关于熊猫测量自条件以来经过的时间的主要内容,如果未能解决你的问题,请参考以下文章