Pandas - 处理时间戳索引及多个时间戳索引的重采样
我有一个比较复杂的问题,下面我来解释一下:
我有一个基础的数据框(DataFrame),如下所示:
value
A B C
111 2024-03-22 00:00:00 2024-03-22 00:00:00 1
111 2024-03-22 00:00:00 2024-03-22 01:00:00 2
111 2024-03-22 00:00:00 2024-03-22 02:00:00 3
222 2024-03-22 00:00:00 2024-03-22 03:00:00 4
222 2024-03-22 00:00:00 2024-03-22 04:00:00 5
222 2024-03-22 00:00:00 2024-03-22 05:00:00 6
从上面的数据可以看到,有一个索引 A
是需要保留的。索引 B
是按天分组的,而索引 C
是按小时分组的。
除了这个基础的数据框,我还有一些日期范围:
a)2024-02-05 00:00:00
2024-02-06 00:00:00
b)
2024-02-05 22:00:00
2024-02-05 23:00:00
2024-02-06 22:00:00
2024-02-06 23:00:00
我想要得到的结果是下面这个数据框:
value
A B C
111 2024-02-05 00:00:00 2024-02-05 22:00:00 0
222 2024-02-05 00:00:00 2024-02-05 22:00:00 0
111 2024-02-05 00:00:00 2024-02-05 23:00:00 0
222 2024-02-05 00:00:00 2024-02-05 23:00:00 0
111 2024-02-06 00:00:00 2024-02-06 22:00:00 0
222 2024-02-06 00:00:00 2024-02-06 22:00:00 0
111 2024-02-06 00:00:00 2024-02-06 23:00:00 0
222 2024-02-06 00:00:00 2024-02-06 23:00:00 0
111 2024-03-22 00:00:00 2024-03-22 00:00:00 1
222 2024-03-22 00:00:00 2024-03-22 00:00:00 0
111 2024-03-22 00:00:00 2024-03-22 01:00:00 2
222 2024-03-22 00:00:00 2024-03-22 01:00:00 0
111 2024-03-22 00:00:00 2024-03-22 02:00:00 3
222 2024-03-22 00:00:00 2024-03-22 02:00:00 0
111 2024-03-22 00:00:00 2024-03-22 03:00:00 0
222 2024-03-22 00:00:00 2024-03-22 03:00:00 4
111 2024-03-22 00:00:00 2024-03-22 04:00:00 0
222 2024-03-22 00:00:00 2024-03-22 04:00:00 5
111 2024-03-22 00:00:00 2024-03-22 05:00:00 0
222 2024-03-22 00:00:00 2024-03-22 05:00:00 6
现在我有几个问题:
- 我该如何实现这些目标呢?
- 使用日期范围(date_range)来提供这些信息是否合适? -> 我唯一的输入是某一天的开始和结束日期以及时间。
还有可能会有一个索引 D,是按分钟分组的。
如果你需要更多信息,请告诉我。
Pandas 版本:2.0.1
提前谢谢你。
问候,Oliver
2 个回答
0
你可以通过这种方式简单地生成 A
、B
和 C
中所有独特值的组合。
import pandas as pd
data = {
'A': [111, 111, 111, 222, 222, 222],
'B': ['2024-03-22 00:00:00', '2024-03-22 00:00:00', '2024-03-22 00:00:00',
'2024-03-22 00:00:00', '2024-03-22 00:00:00', '2024-03-22 00:00:00'],
'C': ['2024-03-22 00:00:00', '2024-03-22 01:00:00', '2024-03-22 02:00:00',
'2024-03-22 03:00:00', '2024-03-22 04:00:00', '2024-03-22 05:00:00'],
'value': [1, 2, 3, 4, 5, 6]
}
df = pd.DataFrame(data)
df['B'] = pd.to_datetime(df['B'])
df['C'] = pd.to_datetime(df['C'])
date_ranges = {
'a': pd.date_range(start='2024-02-05', end='2024-02-06', freq='D'),
'b': pd.date_range(start='2024-02-05 22:00:00', end='2024-02-06 23:00:00', freq='H')
}
unique_combinations = pd.MultiIndex.from_product([df['A'].unique(), date_ranges['a'], date_ranges['b']], names=['A', 'B', 'C'])
all_combinations_df = pd.DataFrame(index=unique_combinations).reset_index()
all_combinations_df['value'] = 0
result_df = pd.concat([df, all_combinations_df]).fillna(0).astype({'value': int})
print(result_df)
这样你就得到了:
A B C value
0 111 2024-03-22 2024-03-22 00:00:00 1
1 111 2024-03-22 2024-03-22 01:00:00 2
2 111 2024-03-22 2024-03-22 02:00:00 3
3 222 2024-03-22 2024-03-22 03:00:00 4
4 222 2024-03-22 2024-03-22 04:00:00 5
.. ... ... ... ...
99 222 2024-02-06 2024-02-06 19:00:00 0
100 222 2024-02-06 2024-02-06 20:00:00 0
101 222 2024-02-06 2024-02-06 21:00:00 0
102 222 2024-02-06 2024-02-06 22:00:00 0
103 222 2024-02-06 2024-02-06 23:00:00 0
[110 rows x 4 columns]
虽然它的排列方式和你期望的输出不一样,但你可以按照自己想要的方式来处理。
0
如果我理解得没错,你需要对现在的数据做一些处理。从数据的角度来看,'B'这一列是基于'C'这一列来的,所以在这个解决方案中,我会先专注于处理'A'和'C'这两列,然后在最后一步重新生成'B'这一列。
数据
from io import StringIO
raw = StringIO('''
A B C value
111 2024-03-22 00:00:00 2024-03-22 00:00:00 1
111 2024-03-22 00:00:00 2024-03-22 01:00:00 2
111 2024-03-22 00:00:00 2024-03-22 02:00:00 3
222 2024-03-22 00:00:00 2024-03-22 03:00:00 4
222 2024-03-22 00:00:00 2024-03-22 04:00:00 5
222 2024-03-22 00:00:00 2024-03-22 05:00:00 6
''')
import pandas as pd
df = pd.read_table(raw, sep='\s{2,}', engine='python', parse_dates=['B', 'C'])
print(df)
# A B C value
# 0 111 2024-03-22 2024-03-22 00:00:00 1
# 1 111 2024-03-22 2024-03-22 01:00:00 2
# 2 111 2024-03-22 2024-03-22 02:00:00 3
# 3 222 2024-03-22 2024-03-22 03:00:00 4
# 4 222 2024-03-22 2024-03-22 04:00:00 5
# 5 222 2024-03-22 2024-03-22 05:00:00 6
解决方案
要解决这个问题,我们需要按照以下步骤进行。
- 创建我们想要包含的额外范围。
- 生成当前'A'和'C'这两列的笛卡尔积。
- 将步骤1和步骤2生成的索引合并在一起。
- 使用新的索引重新索引数据框。
- 生成'B'这一列。
- 调整输出顺序,以符合提问者的具体要求。
additional_ranges = [ # ①
date + pd.Timedelta(hours=hours)
for date in pd.date_range('2024-02-05', '2024-02-06', freq='D')
for hours in [22, 23]
]
new_index = pd.MultiIndex.from_product( # ② & ③
[df['A'].unique(), [*df['C'].unique(), *additional_ranges]],
names=['A', 'C']
)
out = (
df.set_index(['A', 'C']).reindex(new_index, fill_value=0)
.sort_index(level=['C', 'A']) # ④
.assign(B=lambda d: d.index.get_level_values('C').floor('D')) # ⑤
.set_index('B', append=True) # ⑥
.reorder_levels(['A', 'B', 'C'])
)
print(out)
# value
# A B C
# 111 2024-02-05 2024-02-05 22:00:00 0
# 222 2024-02-05 2024-02-05 22:00:00 0
# 111 2024-02-05 2024-02-05 23:00:00 0
# 222 2024-02-05 2024-02-05 23:00:00 0
# 111 2024-02-06 2024-02-06 22:00:00 0
# 222 2024-02-06 2024-02-06 22:00:00 0
# 111 2024-02-06 2024-02-06 23:00:00 0
# 222 2024-02-06 2024-02-06 23:00:00 0
# 111 2024-03-22 2024-03-22 00:00:00 1
# 222 2024-03-22 2024-03-22 00:00:00 0
# 111 2024-03-22 2024-03-22 01:00:00 2
# 222 2024-03-22 2024-03-22 01:00:00 0
# 111 2024-03-22 2024-03-22 02:00:00 3
# 222 2024-03-22 2024-03-22 02:00:00 0
# 111 2024-03-22 2024-03-22 03:00:00 0
# 222 2024-03-22 2024-03-22 03:00:00 4
# 111 2024-03-22 2024-03-22 04:00:00 0
# 222 2024-03-22 2024-03-22 04:00:00 5
# 111 2024-03-22 2024-03-22 05:00:00 0
# 222 2024-03-22 2024-03-22 05:00:00 6