【问题标题】:Integration of pandas timeframe熊猫时间框架的整合
【发布时间】:2022-06-19 13:20:19
【问题描述】:

我想整合以下数据框,这样我就有了每小时的整合价值。我的采样率大约是 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,但我的输出看起来有点奇怪。

谢谢。

【问题讨论】:

  • 您的采样率似乎太长,无法以有意义的精度实现积分。功率波动很大。也许最简单的方法是按小时分组并计算瓦特值的平均值以获得每小时的瓦特小时数。
  • 功率输出只是“虚拟数据”。这样做的主要目的是比较不同模型的总能量输出。为什么采样率会太长?
  • 问题是你的幂函数看起来很不稳定。你真的不知道采样点之间的样子。从一个时间戳到下一个时间戳的增量应该明显小于值本身。如果这不可能,您至少应该利用大数定律,并且每小时进行 5 次以上的观察,以获得每小时的能量有意义的数字。
  • 我明白你关于不稳定函数的观点,我的例子中的值可能有点不具代表性,但这对于如何解决我的编码问题并不重要。而且我确实有10多个观察;每 10 秒进行一次观察,相当于每小时进行 360 次观察。
  • LOL 我把秒和分钟搞混了。

标签: python pandas datetime


【解决方案1】:

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

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()
)

希望对你有帮助

【讨论】:

  • 那么 YOUR_INTEGRATION_FUNCTION 可以是 integrate.trapz() 这里吗?
  • 这不起作用,因为它会将 5 月 5 日和 5 月 6 日的早上 6 点到 7 点放在同一个组中。
  • 确实@Joooeey,我的错! .dt.floor('h') 会将时间戳截断为小时粒度:)
  • @UPetit sweet 我正在寻找类似的东西。这绝对比我做的简单。您可以编辑您的帖子并将其包含在内 ;)
  • 谢谢!它几乎给了我我想要的东西!对于如何实现“YOUR_INTEGRATION_FUNCTION”,我仍然有点茫然。积分.trapz 假设 dx=1,并给出超高的积分值。我可以插入dx = 1/360,但每个小时并不完全有 360 个值。我该如何解决?
【解决方案2】:

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

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 等中间某个位置开始,该怎么办?

【讨论】:

    【解决方案3】:

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

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

    此方案需要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")
    

    注意: 我是楼梯的创造者。如果您有任何反馈或问题,请随时与我们联系。

    【讨论】:

      猜你喜欢
      • 2018-09-24
      • 2019-02-04
      • 2020-05-18
      • 2019-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-03
      • 2022-01-21
      相关资源
      最近更新 更多