6-2 concat的病史叠加


文档摘要

6-2 concat:按轴堆叠的病史叠加 本节摘要:concat沿指定轴把多张表堆成一张:axis=0纵向摞行、axis=1横向拼列,join参数决定不对齐的列与索引怎么处理,ignoreindex重排挂号条。本节顺带交代append的退役始末。 merge是"按内容配对",concat是"按位置堆叠"。十二个月的分表摞成年度总表、订单表旁边拼上气温对照列,都是concat的活。它是堆叠,不问内容:键不参与任何匹配,这一点与merge划清界限。 纵向叠加:月表摞成年表 重号挂号条是纵向叠加的第一事故:后续loc[0]一次叫出两行。摞表默认带上ignoreindex,除非你要用keys追溯来源。 结构不一致时的取舍 outer保信息、inner保整齐。

6-2 concat:按轴堆叠的病史叠加

本节摘要:concat沿指定轴把多张表堆成一张:axis=0纵向摞行、axis=1横向拼列,join参数决定不对齐的列与索引怎么处理,ignore_index重排挂号条。本节顺带交代append的退役始末。

merge是"按内容配对",concat是"按位置堆叠"。十二个月的分表摞成年度总表、订单表旁边拼上气温对照列,都是concat的活。它是堆叠,不问内容:键不参与任何匹配,这一点与merge划清界限

纵向叠加:月表摞成年表

import pandas as pd jan = pd.DataFrame({'门店': ['A', 'B'], '金额': [1280, 960]}) feb = pd.DataFrame({'门店': ['A', 'B'], '金额': [1150, 990]}) # axis=0 默认:行摞行,挂号条保留原样 stacked = pd.concat([jan, feb]) print(stacked) # 门店 金额 # 0 A 1280 # 1 B 960 # 0 A 1150 ← 挂号条重号了 # 1 B 990 # ignore_index=True:重发挂号条 print(pd.concat([jan, feb], ignore_index=True)) # 门店 金额 # 0 A 1280 # 1 B 960 # 2 A 1150 # 3 B 990 # keys参数:给每张来源表挂"上级标签",做多级索引 tagged = pd.concat([jan, feb], keys=['1月', '2月']) print(tagged.loc['2月']) # 门店 金额 # 0 A 1150 # 1 B 990

重号挂号条是纵向叠加的第一事故:后续loc[0]一次叫出两行。摞表默认带上ignore_index,除非你要用keys追溯来源

结构不一致时的取舍

# 2月表多了一列"渠道" feb2 = pd.DataFrame({'门店': ['A', 'B'], '金额': [1150, 990], '渠道': ['线上', '线下']}) # join='outer'默认:列取并集,缺的补NaN print(pd.concat([jan, feb2], ignore_index=True)) # 门店 金额 渠道 # 0 A 1280 NaN # 1 B 960 NaN # 2 A 1150 线上 # 3 B 990 线下 # join='inner':只留公共列 print(pd.concat([jan, feb2], ignore_index=True, join='inner')) # 门店 金额 # 0 A 1280 # 1 B 960 # 2 A 1150 # 3 B 990

outer保信息、inner保整齐。报表口径求整齐用inner,原始归档怕丢字段用outer——同一对参数,两种档案观。

横向拼列:按索引对齐

# axis=1:列挨着列放,按挂号条对齐! weather = pd.DataFrame({'气温': [3, 8]}, index=[0, 1]) print(pd.concat([jan, weather], axis=1)) # 门店 金额 气温 # 0 A 1280 3 # 1 B 960 8 # 挂号条不同就对不上,这是axis=1的第一坑 odd = pd.DataFrame({'湿度': [40]}, index=[1]) print(pd.concat([jan, odd], axis=1)) # 门店 金额 湿度 # 0 A 1280 NaN ← 0号没有湿度 # 1 B 960 40.0

axis=1的"对齐键"是索引本身。日期对不上、重号没重排,拼出来的表就错位。拼列前先确认两边的索引含义一致——时间序列场景里这一条尤其要命,第07章会反复遇到。

append的退役

老代码里常见的df.append(other)在Pandas 1.4被标记废弃、2.0彻底移除。它每次调用都复制整表,循环里append一百次等于复制一百次全量数据。迁移方案一行:

# 旧:result = df1.append(df2) result = pd.concat([df1, df2], ignore_index=True) # 循环攒表的正确姿势:先攒列表,最后一次concat frames = [] for month in range(1, 13): frames.append(load_month(month)) # 各月分表 year = pd.concat(frames, ignore_index=True) print(len(frames), '张月表摞成1张年表')

⚠️ 常见坑:循环里逐次concat虽然比append好些,仍是每次都复制。列表攒齐再一次concat,千张分表能从分钟级降到秒级——这也是第08章性能话题的前菜。

两台归并器械的分工

merge与concat的分工图

维度 merge concat
匹配依据 键的内容 位置或索引
方向 横向为主 两轴皆可
典型场景 订单接会员属性 月表摞年表
行数风险 多对多膨胀 几乎不涨(axis=0)
对齐失控点 脏键静默丢行 索引错位错列

06-6-fig01-5

本节要点回顾

  • axis=0摞行默认join='outer'列取并集,inner保公共列
  • axis=1拼列按索引对齐,索引含义不一致必错位
  • ignore_index防重号,keys保留来源追溯
  • append已退役,循环攒表用列表加末次concat
  • merge与concat的分工:按内容配对找前者,按位置堆叠找后者

追问:月表结构不一致怎么提前发现

十二张月表逐月人工产出,结构漂移几乎必然:某月加了备注列、某月列名改了中文名。摞表前先做一次结构对账,把各表的列集合亮出来比对:

frames = [jan, feb2] # 假设共两张 all_cols = {} for i, f in enumerate(frames): all_cols[i] = set(f.columns) common = set.intersection(*all_cols.values()) union = set.union(*all_cols.values()) print('公共列:', common, '差异列:', union - common) # 公共列: {'门店', '金额'} 差异列: {'渠道'}

差异列的存在不代表必须丢弃,但必须是一个决定而不是一个意外:要么outer保信息、要么inner求整齐,选完在注释里写一句为什么。数据工程的纪律感,多半体现在这些"多写两行让未来的人看懂"的地方。

下一节是归并室的最后一把器械:stack与unstack的床位调整。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U