Pandas 使用日期时间索引重新排列和插值时间序列

Posted

技术标签:

【中文标题】Pandas 使用日期时间索引重新排列和插值时间序列【英文标题】:Pandas rearrange and interpolate time-series based with datetime index 【发布时间】:2021-12-09 08:48:51 【问题描述】:

我有一个反复出现的问题,我每次都无法很好地解决,而且我找不到解决问题的好方法。 假设我有一个索引中包含日期时间的数据框,每 3 小时跨越一次(df1)。我每天都有另一个数据框 (df2)。

我想做两件事:

通过计算一天中每 3 小时周期的平均值,对 df1 进行重新采样,使其每天跨越一次,而不是每 3 小时一次。 对可能丢失的任何一天插入 df2,并将该天添加到它所属的位置。

问题:我使用 for 循环(并希望避免这种情况)并且缺失天数的重采样不完整(只能属性 1 个值)。

这就是我的做法:

import numpy as np
import pandas as pd
from datetime import *

# Create df1
rng = pd.date_range('2000-01-01', periods=365*(24/3), freq='3H')
df1 = pd.DataFrame('Val': np.random.randn(len(rng)) , index = rng)

# Create df2 and drop a few rows
rng2 = pd.date_range('2000-01-01', periods=365, freq='D')
df2 = pd.DataFrame('Val': np.random.randn(len(rng2)) ,index = rng2)
df2 = df2.drop([datetime(2000,1,5),datetime(2000,1,24)])

# Create reference timelist 
date_list = [datetime(2000,1,1) + timedelta(days=x) for x in range(365)]


# Calculate the daily mean of df1:
# We create an array hosting the resampled values of df1
arr = []
c = 1

# Loop that appends the array everytime we hit a new day, and calculate a mean of the day that passed
for i in range(1,len(df1)):

    if c < 365 and df1.index[i] == date_list[c]:
        arr.append(np.mean(df1[i-8:i])[0])
        c = c + 1

# Calculate the last value of the array
arr.append(np.mean(df1[i-7:i+1])[0])

# Create a new dataframe hosting the daily values from df1
df3 = pd.DataFrame('Val': arr, index = rng2)


# Replace missing days in df2
df2 = df2.reindex(date_list, fill_value=0)
df2 = df2.resample('D').interpolate(method='linear') # but this does not work

【问题讨论】:

【参考方案1】:

我认为这两个问题有两个简单的解决方法;您只需要同时更新您对resample 的使用。

第一点:重采样

您的第一点正是使用resample 进行下采样的情况。您可以将 df3 的整个创建替换为:

df1.resample('D').mean()

这将平均每天所有 3 小时的时间段。为了确认,我们可以检查您的结果是否与我建议的结果相同:

>>> all(df1.resample('D').mean().round(8) == df3.round(8))
True

请注意,我必须四舍五入,因为您的代码和resample 之间存在浮点错误;但它们非常接近。

第二点:不要先重新索引

当您在第二种情况下进行插值以填补缺失的日子时,您希望仍然有缺失的日子来填补! AKA,如果您首先 reindex 并用 0 填充值,则插值“失败”,因为它找不到任何插值。因此,如果我正确地解决了您的问题,您只需删除 reindex 行:

# df2 = df2.reindex(date_list, fill_value=0)
df2 = df2.resample('D').interpolate(method='linear')

所以如果你像这样以df2 开头:

>>> df.head(10)
                 Val
2000-01-01  0.235151
2000-01-02  1.279017
2000-01-03 -1.267074
2000-01-04 -0.270182 # the fifth is missing
2000-01-06  0.382649
2000-01-07  0.120253
2000-01-08 -0.223690
2000-01-09  1.379003
2000-01-10 -0.477681
2000-01-11  0.619466

你以这个结束:

>>> df2.head(10)
                 Val
2000-01-01  0.235151
2000-01-02  1.279017
2000-01-03 -1.267074
2000-01-04 -0.270182
2000-01-05  0.056233 # the fifth is here, halfway between 4th and 6th
2000-01-06  0.382649
2000-01-07  0.120253
2000-01-08 -0.223690
2000-01-09  1.379003
2000-01-10 -0.477681

【讨论】:

感谢您提供的这些好例子!

以上是关于Pandas 使用日期时间索引重新排列和插值时间序列的主要内容,如果未能解决你的问题,请参考以下文章

Pandas:在多索引数据帧中重新索引和插值

Python Pandas 插值:在缺失的日期范围内重新分配值

Pandas - 根据之前的行为进行插值

Pandas 使用其他不规则时间列表重新采样和插值不规则时间序列

pandas DataFrame 从不规则时间序列索引中重新采样

Pandas 从重采样中检索添加行的索引