熊猫测量自条件以来经过的时间

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

这个想法是提取秒部分并从状态从“关闭”变为“开启”的第一时刻减去经过的时间。这是使用transformfirst 完成的。

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 firsttransform

(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

【讨论】:

以上是关于熊猫测量自条件以来经过的时间的主要内容,如果未能解决你的问题,请参考以下文章

如何测量 QML 项目自加载以来出现在屏幕上所用的时间?

获取自上次增加 Prometheus 计数器以来经过的时间

以纳秒为单位测量纪元时间 - Android

Python - 如何计算自 X 日期以来经过的时间?

如何计算自特定列中发生事件以来经过的时间 - Pandas DataFrames

显示自最近的数据库 DateTime 以来经过的时间,并每隔一秒增加一次