Pandas - 处理时间戳索引及多个时间戳索引的重采样

0 投票
2 回答
37 浏览
提问于 2025-04-12 17:30

我有一个比较复杂的问题,下面我来解释一下:

我有一个基础的数据框(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

你可以通过这种方式简单地生成 ABC 中所有独特值的组合。

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

解决方案

要解决这个问题,我们需要按照以下步骤进行。

  1. 创建我们想要包含的额外范围。
  2. 生成当前'A'和'C'这两列的笛卡尔积。
  3. 将步骤1和步骤2生成的索引合并在一起。
  4. 使用新的索引重新索引数据框。
  5. 生成'B'这一列。
  6. 调整输出顺序,以符合提问者的具体要求。
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

撰写回答