You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合并带时间切片的DataFrame:填充无Grade时段并拆分重叠行

解决思路与实现代码

核心思路

不用循环分组,而是通过交叉连接+时间区间计算高效处理,步骤如下:

  1. 将DF1和DF2按Country+City做交叉连接,覆盖所有可能的组合;
  2. 计算每个组合的时间重叠区间,筛选出有重叠的记录;
  3. 拆分DF1中与Grade区间重叠的部分,同时保留DF1中无重叠的原始区间(对应DF2字段为空);
  4. 合并所有结果,得到符合要求的最终DataFrame。

代码实现

首先导入必要库:

import pandas as pd

定义原始DataFrame(修正DF2字段拼写错误:Garde_Validity_End→Grade_Validity_End):

df1 = pd.DataFrame({
    "Country": ['USA', 'USA','USA','UK','UK','UK'],
    "City": ['NYC','NYC','NYC','London','London','London'],
    "Start_Range": pd.to_datetime(['2016-01-01', '2020-07-01','2022-01-01','2019-01-01','2021-01-01','2023-01-01']),
    "End_Range": pd.to_datetime(['2020-06-30', '2021-12-31','2023-12-31','2020-12-31','2022-12-31','2023-12-31'])
})

df2 = pd.DataFrame({
    "Country": ['USA', 'USA','UK'],
    "City": ['NYC','NYC','London'],
    "Grade_Validity_Begin": pd.to_datetime(['2021-10-01','2023-01-01','2021-10-01']),
    "Grade_Validity_End": pd.to_datetime(['2022-12-31', '2099-12-31','2023-12-31'])
})

步骤1:交叉连接并计算重叠区间

# 按Country和City做交叉连接,保留DF1的所有行
cross_join = df1.merge(df2, on=['Country', 'City'], how='left')

# 计算每个组合的重叠区间起止时间
cross_join['overlap_start'] = cross_join[['Start_Range', 'Grade_Validity_Begin']].max(axis=1)
cross_join['overlap_end'] = cross_join[['End_Range', 'Grade_Validity_End']].min(axis=1)

# 筛选出存在时间重叠的记录
has_overlap = cross_join[cross_join['overlap_start'] <= cross_join['overlap_end']].copy()

# 提取重叠部分的有效行,替换时间区间为重叠区间
overlap_rows = has_overlap.rename(columns={
    'overlap_start': 'Start_Range',
    'overlap_end': 'End_Range'
})[['Country', 'City', 'Start_Range', 'End_Range', 'Grade_Validity_Begin', 'Grade_Validity_End']]

步骤2:提取DF1中无重叠的区间部分

# 标记DF1中哪些行存在至少一个重叠
df1_with_flag = df1.merge(
    has_overlap[['Country', 'City', 'Start_Range', 'End_Range']].drop_duplicates(),
    on=['Country', 'City', 'Start_Range', 'End_Range'],
    how='left',
    indicator=True
)

# 情况1:DF1中完全没有对应Grade的行
no_grade_rows = df1_with_flag[df1_with_flag['_merge'] == 'left_only'].copy()
no_grade_rows[['Grade_Validity_Begin', 'Grade_Validity_End']] = pd.NA
no_grade_rows = no_grade_rows.drop(columns='_merge')

# 情况2:DF1中有部分区间与Grade重叠,拆分出不重叠的前后段
split_rows = []
for _, row in has_overlap.iterrows():
    # 重叠前的区间:若DF1起始早于重叠起始,保留该段
    if row['Start_Range'] < row['overlap_start']:
        split_rows.append({
            'Country': row['Country'],
            'City': row['City'],
            'Start_Range': row['Start_Range'],
            'End_Range': row['overlap_start'] - pd.Timedelta(days=1),
            'Grade_Validity_Begin': pd.NA,
            'Grade_Validity_End': pd.NA
        })
    # 重叠后的区间:若DF1结束晚于重叠结束,保留该段
    if row['End_Range'] > row['overlap_end']:
        split_rows.append({
            'Country': row['Country'],
            'City': row['City'],
            'Start_Range': row['overlap_end'] + pd.Timedelta(days=1),
            'End_Range': row['End_Range'],
            'Grade_Validity_Begin': pd.NA,
            'Grade_Validity_End': pd.NA
        })

split_df = pd.DataFrame(split_rows)

步骤3:合并所有结果

# 合并三类行:重叠行、无Grade行、拆分出的无重叠行
final_df = pd.concat([overlap_rows, no_grade_rows, split_df], ignore_index=True)

# 按国家、城市、起始时间排序,让结果更规整
final_df = final_df.sort_values(by=['Country', 'City', 'Start_Range']).reset_index(drop=True)

最终结果说明

最终的final_df完全满足需求:

  • DF1中无对应Grade的时间区间,Grade_Validity_Begin和Grade_Validity_End为空;
  • Grade有效时段与DF1切片重叠的部分,完整保留Grade字段;
  • DF1被Grade区间拆分后的剩余无重叠部分,Grade字段为空。

内容的提问来源于stack exchange,提问作者Zara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 16:16:06