假设我有一个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)
event_time | some_metric | 秒_直到_下一次 |
---|---|---|
2021-02-24 20:53:14.572000+00:00 | 2362 | 553.995 |
2021-02:28.567000+00:00 | 4264 | 1.005 |
2021-02:29.572000+000:00 | 5160 | 0.989 |
2021-02:30.561000+000:00 | 6183 | 85.045 |
2021-02-24 21:03:55.606000+000:00 | 9654 | >td style="text align:right">nan