【问题标题】:How to "expand" multi-index with date_range in pandas?如何在 pandas 中使用 date_range 来“扩展”多索引?
【发布时间】:2023-02-22 19:00:17
【问题描述】:

我有一个看起来像这样的输入数据框: enter image description here

并使用 pandas (v1.3.2) 像这样生成

import pandas as pd
import datetime

input_data = [
    ["1", datetime.datetime(2023,2,21,20,0,0), 10],
    ["1", datetime.datetime(2023,2,21,20,30,0), 10],
    ["2", datetime.datetime(2023,2,21,15,0,0), 15],
    ["2", datetime.datetime(2023,2,21,15,30,0), 15],
]

df_input = pd.DataFrame(data=input_data, columns=["id", "time", "duration"]).set_index(["id", "time"])

我想根据时隙持续时间(“持续时间”列)“扩展”我的数据帧的第二级(索引列“时间”)。输出数据框应该是这样的: enter image description here

第一个 id ("1") 的更多解释:我想要从 20:00 到 20:30 -> 20:00、20:10、20:20、20:30 的所有时隙持续 10 分钟。

我想出了一个解决方案(请参阅下面的代码 sn-p),但它很慢,我想知道 pandas 中是否有更快的内置功能来帮助我处理这个问题。

import pandas as pd
import datetime

input_data = [
    ["1", datetime.datetime(2023,2,21,20,0,0), 10],
    ["1", datetime.datetime(2023,2,21,20,30,0), 10],
    ["2", datetime.datetime(2023,2,21,15,0,0), 15],
    ["2", datetime.datetime(2023,2,21,15,30,0), 15],
]

df_input = pd.DataFrame(data=input_data, columns=["id", "time", "duration"]).set_index(["id", "time"])

df_output = pd.DataFrame()

for i in range(0, df_input.shape[0], 2):
    start_at = df_input.index[i][1]
    end_at = df_input.index[i+1][1]
    duration = df_input.iloc[i]["duration"]
    
    df_cut = pd.DataFrame(
        pd.date_range(
            start=start_at,
            end=end_at,
            freq=f"{duration}min",
        ).rename("start_at_converted")
    )
    df_cut["id"] = df_input.index[i][0]
    df_cut["duration"] = duration
    
    df_output = pd.concat((df_output, df_cut), axis=0)

df_output = df_output.set_index(["id", "start_at_converted"])

感谢您的帮助 !

【问题讨论】:

    标签: python pandas multi-index date-range


    【解决方案1】:

    你可以使用groupby.resample

    freq = {'1': '10min', '2': '15min'}
    
    out = (df_input.reset_index('id').groupby('id')
           .apply(lambda g: g.resample(freq[g.name]).ffill())
           .drop(columns='id')
           # optional, to rename the index
           .rename_axis(('id', 'start_at_converted'))
          )
    

    输出:

                            duration
    id start_at_converted           
    1  2023-02-21 20:00:00        10
       2023-02-21 20:10:00        10
       2023-02-21 20:20:00        10
       2023-02-21 20:30:00        10
    2  2023-02-21 15:00:00        15
       2023-02-21 15:15:00        15
       2023-02-21 15:30:00        15
    

    如果你只有一个频率:

    out = (df_input.reset_index('id').groupby('id')
           .resample('15min').ffill().drop(columns='id')
           # optional, to rename the index
           #.rename_axis(('id', 'start_at_converted'))
          )
    

    输出:

                            duration
    id time                         
    1  2023-02-21 20:00:00        10
       2023-02-21 20:15:00        10
       2023-02-21 20:30:00        10
    2  2023-02-21 15:00:00        15
       2023-02-21 15:15:00        15
       2023-02-21 15:30:00        15
    

    【讨论】:

    • 我有多个频率,所以我将使用第一个工作得很好的解决方案。感谢您快速有效的答复。
    • @Florian 请注意,如果需要,您可以从原始 DataFrame 创建频率字典
    猜你喜欢
    • 2018-07-19
    • 2019-03-10
    • 2015-01-07
    • 2013-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-17
    相关资源
    最近更新 更多