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

如何在Pandas中无循环按条件复制拆分数据行?

Pandas高效拆分日期区间行(无循环实现)

原始数据集

trade_id  start_date end_date factset_entity_id  product_id  \
0  100000191        2017      NaT          0711GY-E    99996362   
1  100000193        2017     2018          0711GY-E    99996413   
2  100000193        2018     2022          0711GY-E    99996413   
3  100000193        2022      NaT          0711GY-E    99996413   
4  100000231        2016     2018          05NC3S-E    59979529   

                          product_name         l6_id  multi_assign_flag  
0                  Fan Milk - FanYogo  5.015152e+11                 0.0  
1  Fan Milk - FanDango/Frozen FanDango  5.015151e+11                 0.0  
2               Fan Milk - FanDango  5.015151e+11                 0.0  
3               Fan Milk - FanDango  5.015151e+11                 0.0  
4      Ci:z Holdings - Dr. Ci:Labo  5.020102e+11                 1.0  

需求说明

对start_date与end_date均不为空且不相等的行,拆分成两行:分别将start_date和end_date作为单独的年份值,其余字段保持不变,最终移除原start_date和end_date列,将年份列放在首位。

例如原行:

1  100000193        2017     2018          0711GY-E    99996413  Fan Milk - FanDango/Frozen FanDango  5.015151e+11                 0.0

需转换为:

2017  100000193          0711GY-E    99996413  Fan Milk - FanDango/Frozen FanDango  5.015151e+11                 0.0
2018  100000193          0711GY-E    99996413  Fan Milk - FanDango/Frozen FanDango  5.015151e+11                 0.0

无循环实现方案

方案一:concat拆分法(性能最优,适合大数据集)

通过concat分别处理需要拆分和不需要拆分的行,全程采用矢量化操作,避免循环:

import pandas as pd

# 构造示例数据(实际使用时替换为你的数据读取逻辑)
data = {
    'trade_id': [100000191, 100000193, 100000193, 100000193, 100000231],
    'start_date': [2017, 2017, 2018, 2022, 2016],
    'end_date': [pd.NaT, 2018, 2022, pd.NaT, 2018],
    'factset_entity_id': ['0711GY-E', '0711GY-E', '0711GY-E', '0711GY-E', '05NC3S-E'],
    'product_id': [99996362, 99996413, 99996413, 99996413, 59979529],
    'product_name': ['Fan Milk - FanYogo', 'Fan Milk - FanDango/Frozen FanDango', 'Fan Milk - FanDango', 'Fan Milk - FanDango', 'Ci:z Holdings - Dr. Ci:Labo'],
    'l6_id': [5.015152e+11, 5.015151e+11, 5.015151e+11, 5.015151e+11, 5.020102e+11],
    'multi_assign_flag': [0.0, 0.0, 0.0, 0.0, 1.0]
}
df = pd.DataFrame(data)

# 筛选需要拆分的行:end_date不为空且与start_date不等
mask = df['end_date'].notna() & (df['start_date'] != df['end_date'])

# 拆分需要处理的行:复制两次,分别将year设为start_date和end_date
split_part = pd.concat([
    df[mask].assign(year=df['start_date']),
    df[mask].assign(year=df['end_date'])
])

# 处理不需要拆分的行:直接将year设为start_date
non_split_part = df[~mask].assign(year=df['start_date'])

# 合并两部分数据,重置索引并调整列顺序
result = pd.concat([split_part, non_split_part]).reset_index(drop=True)
result = result[['year', 'trade_id', 'factset_entity_id', 'product_id', 'product_name', 'l6_id', 'multi_assign_flag']]

# 输出结果
print(result)

方案二:explode展开法(代码简洁,易理解)

通过为每行生成年份列表,再用explode展开列表实现拆分:

import pandas as pd

# 构造示例数据(同上)
df = pd.DataFrame(data)

# 标记需要拆分的行
mask = df['end_date'].notna() & (df['start_date'] != df['end_date'])

# 为每行生成对应的年份列表:需要拆分的行生成[start, end],否则生成[start]
df['year'] = df.apply(
    lambda x: [x['start_date'], x['end_date']] if mask.loc[x.name] else [x['start_date']],
    axis=1
)

# 展开年份列表,重置索引并调整列顺序
result = df.explode('year').reset_index(drop=True)
result = result[['year', 'trade_id', 'factset_entity_id', 'product_id', 'product_name', 'l6_id', 'multi_assign_flag']]

# 输出结果
print(result)

最终结果

两种方案都会得到如下格式的输出:

year  trade_id factset_entity_id  product_id  \
0  2017  100000193          0711GY-E    99996413   
1  2018  100000193          0711GY-E    99996413   
2  2018  100000193          0711GY-E    99996413   
3  2022  100000193          0711GY-E    99996413   
4  2016  100000231          05NC3S-E    59979529   
5  2018  100000231          05NC3S-E    59979529   
6  2017  100000191          0711GY-E    99996362   
7  2022  100000193          0711GY-E    99996413   

                          product_name         l6_id  multi_assign_flag  
0  Fan Milk - FanDango/Frozen FanDango  5.015151e+11                 0.0  
1  Fan Milk - FanDango/Frozen FanDango  5.015151e+11                 0.0  
2               Fan Milk - FanDango  5.015151e+11                 0.0  
3               Fan Milk - FanDango  5.015151e+11                 0.0  
4      Ci:z Holdings - Dr. Ci:Labo  5.020102e+11                 1.0  
5      Ci:z Holdings - Dr. Ci:Labo  5.020102e+11                 1.0  
6                  Fan Milk - FanYogo  5.015152e+11                 0.0  
7               Fan Milk - FanDango  5.015151e+11                 0.0  

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 22:20:35