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
将是具有 IntervalIndex
和 Timedelta
值的 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")
我想集成以下数据框,这样我就有了每小时的集成值。我的采样率大约是 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
将是具有 IntervalIndex
和 Timedelta
值的 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")