将后续索引值之间经过的秒数分配给新列



假设我有一个Pandas数据帧,其中索引是日期时间值。我想添加一列,用于计算每个后续记录之间经过的total_seconds。

问题设置:

import pandas as pd
df = pd.DataFrame(
    data=[
        ["2021-02-24 20:53:14.572000+00:00", "2362"],
        ["2021-02-24 21:02:28.567000+00:00", "4264"],
        ["2021-02-24 21:02:29.572000+00:00", "5160"],
        ["2021-02-24 21:02:30.561000+00:00", "6183"],
        ["2021-02-24 21:03:55.606000+00:00", "9654"],
    ],
    columns=["event_time", "some_metric"],
)
# Make the timestamp our index and make sure the events are in order.
df["event_time"] = pd.to_datetime(df["event_time"])
df = df.set_index("event_time")
df = df.sort_index()

现在我的数据帧是这样的:

                                 some_metric
                      event_time    
2021-02-24 20:53:14.572000+00:00    2362
2021-02-24 21:02:28.567000+00:00    4264
2021-02-24 21:02:29.572000+00:00    5160
2021-02-24 21:02:30.561000+00:00    6183
2021-02-24 21:03:55.606000+00:00    9654

现在,我想添加一个新列,它是距离下一个事件所用的秒数。

以下是我正在尝试的,它运行时没有错误::

df["seconds_until_next"] = (
    df.reset_index()["event_time"].shift(-1) - df.reset_index()["event_time"]
).dt.total_seconds()

但是生成的数据帧看起来是这样的,所有的NaN都在新列中:

                                 some_metric    seconds_until_next
                      event_time
2021-02-24 20:53:14.572000+00:00    2362              NaN
2021-02-24 21:02:28.567000+00:00    4264              NaN
2021-02-24 21:02:29.572000+00:00    5160              NaN
2021-02-24 21:02:30.561000+00:00    6183              NaN
2021-02-24 21:03:55.606000+00:00    9654              NaN

这很奇怪,因为仅仅运行该操作的右侧看起来就返回了我想要的值:

(df.reset_index()["event_time"].shift(-1) - df.reset_index()["event_time"]).dt.total_seconds()

退货:

0    553.995
1      1.005
2      0.989
3     85.045
4        NaN
Name: event_time, dtype: float64

这是怎么回事?我认为这是因为等号左侧的df和右侧的结果之间的索引值不匹配?我该如何解决?

更新:这些答案很好,希望我能给大家打分。我觉得我错过的神奇知识是.to_series()。一定会记住其他建议。这种方式很有效,在我的大脑中感觉很好,不确定它是否是最具表现力的:

df["seconds_until_next"] = (
    df.index.to_series().shift(-1) - df.index.to_series()
).dt.total_seconds()

diff(而不是shift的加法和减法(类似(但略为简洁(的选项:

df['seconds_until_next'] = -df.index.to_series().diff(-1).dt.total_seconds()
df

输出:

                                 some_metric  seconds_until_next
event_time                                                      
2021-02-24 20:53:14.572000+00:00        2362             553.995
2021-02-24 21:02:28.567000+00:00        4264               1.005
2021-02-24 21:02:29.572000+00:00        5160               0.989
2021-02-24 21:02:30.561000+00:00        6183              85.045
2021-02-24 21:03:55.606000+00:00        9654                 NaN

这是因为当您执行reset_index时,您会得到一个不同的索引(RangeIndex(,它与原始df不对齐,并且您会得到所有NaN值。尝试to_series:

df['time_gap'] = df.index.to_series().shift(-1).sub(df.index).dt.total_seconds()

输出:

                                 some_metric  time_gap
event_time                                            
2021-02-24 20:53:14.572000+00:00        2362   553.995
2021-02-24 21:02:28.567000+00:00        4264     1.005
2021-02-24 21:02:29.572000+00:00        5160     0.989
2021-02-24 21:02:30.561000+00:00        6183    85.045
2021-02-24 21:03:55.606000+00:00        9654       NaN

有一个微妙的问题-范围索引与日期时间索引不匹配。通过使其成为具有.values 的阵列来解决问题

df.assign(seconds_until_next=(pd.Series(df.index).shift(-1) - df.index).dt.total_seconds().values)
>td style="text align:right">nan
event_timesome_metric秒_直到_下一次
2021-02-24 20:53:14.572000+00:002362553.995
2021-02:28.567000+00:0042641.005
2021-02:29.572000+000:0051600.989
2021-02:30.561000+000:00618385.045
2021-02-24 21:03:55.606000+000:009654

最新更新