【问题标题】:Pandas: how to convert an incomplete date-only index to hourly indexPandas:如何将不完整的仅日期索引转换为每小时索引
【发布时间】:2020-10-28 20:37:03
【问题描述】:

我有一个理想的每小时时间序列,如下所示:

from pandas import Series, date_range, Timestamp
from numpy import random

index = date_range(
    "2020-01-26 14:00:00",
    "2020-11-28 02:00:00",
    freq="H",
    tz="Europe/Madrid",
)
ideal = Series(index=index, data=random.rand(len(index)))
ideal
2020-01-26 14:00:00+01:00    0.186026
2020-01-26 15:00:00+01:00    0.142096
2020-01-26 16:00:00+01:00    0.432625
2020-01-26 17:00:00+01:00    0.373805
2020-01-26 18:00:00+01:00    0.377718
                               ...   
2020-11-27 22:00:00+01:00    0.961327
2020-11-27 23:00:00+01:00    0.440274
2020-11-28 00:00:00+01:00    0.996126
2020-11-28 01:00:00+01:00    0.607873
2020-11-28 02:00:00+01:00    0.122993
Freq: H, Length: 7357, dtype: float64

实际的、非理想的时间序列远非完美:

  • 不完整(即:缺少一些小时值)
  • 只存储日期,不存储小时

类似这样的:

actual = ideal.drop([
    Timestamp("2020-01-28 01:00:00", tz="Europe/Madrid"),
    Timestamp("2020-08-02 15:00:00", tz="Europe/Madrid"),
    Timestamp("2020-08-02 16:00:00", tz="Europe/Madrid"),
])
actual.index = actual.index.date
actual
2020-01-26    0.186026
2020-01-26    0.142096
2020-01-26    0.432625
2020-01-26    0.373805
2020-01-26    0.377718
                ...   
2020-11-27    0.961327
2020-11-27    0.440274
2020-11-28    0.996126
2020-11-28    0.607873
2020-11-28    0.122993
Length: 7355, dtype: float64

现在我想将实际时间序列转换为尽可能接近理想的时间序列。这意味着:

  • 生成的系列具有完整的每小时索引(即:没有缺失值)
  • 如果无法填满一小时,则允许使用 NaN(即:实际时间序列中缺少它)
  • 仅在缺少数据的那些日子里,预计一天内与理想时间序列的偏差

有没有一种有效的方法来做到这一点?我想避免迭代,因为我猜这会非常低效。

由于效率高,我正在寻找一种仅依赖于 Python/Pandas/NumPy(不允许 Cython 或 Numba)的快速(CPU wall time)实现。

【问题讨论】:

  • 问题出在2020-08-02 你有 22 行。从actual 中你怎么知道15:00:0016:00:00,而不是1:00:0010:00:00,不见了?
  • @QuangHoang 我不知道,也不会在意。如前所述,在缺少数据的那些日子里,预计一天内与理想时间序列的偏差。这意味着我知道会丢失 2 个值,但我不在乎它们是放在一天的开始、结束还是中间。

标签: python pandas


【解决方案1】:

您可以使用groupby().cumcount() 表示一天中的小时,然后重新索引:

s = pd.to_datetime(actual.index).tz_localize("Europe/Madrid").to_series()
actual.index = s + s.groupby(level=0).cumcount() * pd.Timedelta('1H')

new_idx = pd.date_range(actual.index.min(),actual.index.max(), freq='H')
actual = actual.reindex(new_idx)

【讨论】:

  • 如果我只执行您提供的代码,我想我会得到ValueError: cannot reindex from a duplicate axis,但我明白了,非常感谢! ^^您可以在接受之前更新答案以避免此错误吗?
  • 我也在查看错误。这可能是由于夏令时,发生在两个 2020-10-27 01:00:00 时间戳。
  • 是的,我正在使用tz="Europe/Madrid",并且由于 DST,这可能会发生(我故意让 DST 天数保持不变,因为其中一个是 25 小时并且有一个“重复”小时)。跨度>
  • 我编辑了您的答案以修复本地化索引,希望您不介意。再次感谢! ^^
  • @Peque 谢谢,这很简单。我学到了新东西。
猜你喜欢
  • 2018-10-30
  • 2012-10-07
  • 2016-04-26
  • 2020-01-16
  • 1970-01-01
  • 2021-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多