pandas 时间范围的整合

Integration of pandas timeframe

我想集成以下数据框,这样我就有了每小时的集成值。我的采样率大约是 10 秒,但如果需要均匀的时间间隔,我想我可以使用 df.resample().

Timestamp                    Power [W]
2022-05-05 06:00:05+02:00    2.0
2022-05-05 06:00:15+02:00    1.2
2022-05-05 06:00:25+02:00    0.3
2022-05-05 06:00:35+02:00    4.3
2022-05-05 06:00:45+02:00    1.1
                            ... 
2022-05-06 20:59:19+02:00    1.4
2022-05-06 20:59:29+02:00    2.0
2022-05-06 20:59:39+02:00    4.1
2022-05-06 20:59:49+02:00    1.3
2022-05-06 20:59:59+02:00    0.8

所以我希望能够在数小时和数天内进行集成,因此我的输出可能如下所示:

Timestamp                    Energy [Wh]
2022-05-05 07:00:00+02:00    some values
2022-05-05 08:00:00+02:00    .
2022-05-05 09:00:00+02:00    .
2022-05-05 10:00:00+02:00    .
2022-05-05 11:00:00+02:00    
                            ... 
2022-05-06 20:00:00+02:00    
2022-05-06 21:00:00+02:00    

(小时 07:00 是包含 06:00-07:00 之间的值,依此类推...)

Timestamp      Energy [Wh]
2022-05-05     .
2022-05-06     .

那么我该如何实现呢?我在想我可以使用 scipy.integrate,但我的输出看起来有点奇怪。

谢谢。

您可以创建一个新列来表示您的时间戳被截断为小时数:

df['Timestamp_hour'] = df['Timestamp'].dt.floor('h')

请注意,在这种情况下,6.00 点到 6.59 点之间的行将包含在第 6 小时而不是第 7 小时。

然后您可以在应用积分计算之前按新列对行进行分组:

df_integrated_hour = (
    df
    .groupby('Timestamp_hour')
    .agg({
        'Power': YOUR_INTEGRATION_FUNCTION
    })
    .rename(columns={'Power': 'Energy'})
    .reset_index()
)

希望对您有所帮助

这是一个非常简单的解决方案,使用矩形积分,矩形从零开始以 10 秒为间隔间隔,因此不完全以数据点为中心(假设数据以固定间隔传送并且没有数据丢失),a.k.a。一个简单的平均值。

from numpy import random
import pandas as pd

times = pd.date_range('2022-05-05 06:00:04+02:00', '2022-05-06 21:00:00+02:00', freq='10S')
watts = random.rand(len(times)) * 5
df = pd.DataFrame(index=times, data=watts, columns=["Power [W]"])

hourly = df.groupby([df.index.date, df.index.hour]).mean()
hourly.columns = ["Energy [Wh]"]
print(hourly)

hours_in_a_day = 24  # add special casing for leap days here, if required
daily = df.groupby(df.index.date).mean()
daily.columns = ["Energy [Wh]"]
print(daily)

输出:

               Energy [Wh]
2022-05-05 6      2.625499
           7      2.365678
           8      2.579349
           9      2.569170
           10     2.543611
           11     2.742332
           12     2.478145
           13     2.444210
           14     2.507821
           15     2.485770
           16     2.414057
           17     2.567755
           18     2.393725
           19     2.609375
           20     2.525746
           21     2.421578
           22     2.520466
           23     2.653466
2022-05-06 0      2.559110
           1      2.519032
           2      2.472282
           3      2.436023
           4      2.378289
           5      2.549572
           6      2.558478
           7      2.470721
           8      2.429454
           9      2.390543
           10     2.538194
           11     2.537564
           12     2.492308
           13     2.387632
           14     2.435582
           15     2.581616
           16     2.389549
           17     2.461523
           18     2.576084
           19     2.523577
           20     2.572270
            Energy [Wh]
2022-05-05    60.597007
2022-05-06    59.725029

梯形积分应该给出稍微好一点的近似值,但更难正确实施。你必须小心处理小时界限。这基本上只是在整点(在 09:59:59.999 和 10:00:00 处)插入两次内插值的问题。但是你还必须想出一种方法来推断范围的开始和结束,即在你的例子中从 06:00:05 到 06:00:00。但是要小心,如果你的测量值只是从中间的某个地方开始,比如 06:17:23?

怎么办?

此解决方案使用名为 staircase 的程序包,它是 pandas 生态系统的一部分,其存在是为了更轻松地处理阶跃函数(即分段常数)。

它将从 pandas.Series 创建一个 Stairs 对象(代表阶梯函数),然后对任意 DatetimeIndex 值进行分箱,然后积分。

此方案需要staircase 2.4.2或以上

设置

df = pd.DataFrame(
    {
        "Timestamp":pd.to_datetime(
            [
                "2022-05-05 06:00:05+02:00",
                "2022-05-05 06:00:15+02:00",
                "2022-05-05 06:00:25+02:00",
                "2022-05-05 06:00:35+02:00",
                "2022-05-05 06:00:45+02:00",
            ]
        ),
        "Power [W]":[2.0, 1.2, 0.3, 4.3, 1.1]
    }
)

解决方案

import staircase as sc

# create step function
sf = sc.Stairs.from_values(
    initial_value=0,
    values=df.set_index("Timestamp")["Power [W]"],
)

# optional: plot
sf.plot(style="hlines")

# create the bins (datetime index) over which you want to integrate
# using 20s intervals in this example
bins = pd.date_range(
    "2022-05-05 06:00:00+02:00", "2022-05-05 06:01:00+02:00", freq="20s"
)

# slice into bins and integrate
result = sf.slice(bins).integral()

result 将是具有 IntervalIndexTimedelta 值的 pandas.Series。 IntervalIndex 保留时区信息,只是不显示它:

[2022-05-05 06:00:00, 2022-05-05 06:00:20)          0 days 00:00:26
[2022-05-05 06:00:20, 2022-05-05 06:00:40)   0 days 00:00:30.500000
[2022-05-05 06:00:40, 2022-05-05 06:01:00)          0 days 00:00:38
dtype: timedelta64[ns]

您可以像这样将索引更改为“左”值(并查看此时区信息):

result.index = result.index.left

您可以将值更改为除以适当 Timedelta 的浮点数。例如转换为分钟:

result/pd.Timedelta("1min")