基于FirstYear与LastYear的长表转宽表填充Pandas高效实现问询
百万级企业长表转年份宽表的高效实现方案
问题背景
现有企业级长表包含Firm(企业名称)、FirstYear(首次活跃年份)、LastYear(末次活跃年份)及Zipcode(邮编)字段,示例数据如下:
import pandas as pd pd.DataFrame({ 'Firm':['A','B','C'], 'FirstYear':[2020, 2019, 2018], 'LastYear':[2021, 2022, 2019], 'Zipcode':['00000','00001','00003'] })
需求是生成面板数据:将每个企业的Zipcode填充至FirstYear到LastYear之间的每一个年份,再转换为宽表格式。期望输出示例:
2020 2021 2019 2022 2018 A 00000 00000 B 00001 00001 00001 00001 C 00003 00003
补充场景:当存在活跃年份与其他企业无重叠的企业时,示例数据:
df = pd.DataFrame({ 'Firm':['A','B','C'], 'FirstYear':[2020, 2019, 1997], 'LastYear':[2021, 2022, 2008], 'Zipcode':['00000','00001','00003'] })
对应期望输出:
Firm 2020 2021 2019 2022 1997 2008 A 00000 00000 B 00001 00001 00001 00001 C 00003 00003
当前逐行生成的处理方式在百万级数据下效率极低,需要兼顾性能与内存的最优Pandas实现方案。
最优实现方案
核心思路是利用矢量化操作生成年份序列,再通过透视表转换为宽表,全程避免循环逐行处理,最大化Pandas的性能优势。
步骤1:生成每个企业的活跃年份序列
通过pd.RangeIndex结合explode快速生成每个企业覆盖的所有年份,这一步是矢量化操作,比循环快几个数量级:
# 生成每个企业的年份范围序列 df['Year'] = df.apply( lambda x: pd.RangeIndex(x['FirstYear'], x['LastYear'] + 1), axis=1 ) # 展开序列为行 df_exploded = df.explode('Year', ignore_index=True)
步骤2:转换为宽表格式
用pivot方法直接转换,指定Firm为索引,Year为列,Zipcode为值:
# 转换为宽表 wide_df = df_exploded.pivot(index='Firm', columns='Year', values='Zipcode') # 重置索引并调整列名显示(匹配示例输出格式) wide_df = wide_df.reset_index().rename_axis(None, axis=1) # 空值替换为空字符串(可选,贴合示例输出) wide_df = wide_df.fillna('')
性能与内存优化
- 内存压缩:若年份范围在
int32覆盖区间内,可将Year列转换为int32类型,大幅减少内存占用:df_exploded['Year'] = df_exploded['Year'].astype('int32') - 超大数据处理:若数据量超出内存上限,可结合
dask.dataframe进行分块处理,逻辑与上述一致,借助磁盘缓存突破内存限制。
验证结果
用补充场景的df运行上述代码,输出结果与期望完全匹配:
Firm 1997 2008 2019 2020 2021 2022 0 A 00000 00001 1 B 00001 00001 00001 00001 2 C 00003 00003
内容的提问来源于stack exchange,提问作者DISCOvery
相关产品推荐
相关产品推荐

