6-1 merge的交叉配对


文档摘要

6-1 merge:按键交叉配对 本节摘要:merge按一个或多个键把两张表横向拼接,how参数决定对不上的行的去留,indicator标注每行的来源,validate预防多对多膨胀。本节的核心观点:how不是技术选项,是业务口径。 归并室的第一台器械。订单表想带上会员等级,就像把两本病历按身份证号订在一起:号对上了,两本的内容都归这一行。 最小可用配对 inner把两头都对不上的行全丢了:T04(脏键)和M31(沉睡会员)同时消失。这正是默认参数的危险——你什么都没感觉到,数据已经少了。 四种口径,四份报告 indicator=True给每行挂来源标:both两边都有、leftonly只有左表。归并后先看merge的分布再下结论,是这章最重要的习惯——脏键、沉睡会员,一眼现形。

6-1 merge:按键交叉配对

本节摘要:merge按一个或多个键把两张表横向拼接,how参数决定对不上的行的去留,indicator标注每行的来源,validate预防多对多膨胀。本节的核心观点:how不是技术选项,是业务口径。

归并室的第一台器械。订单表想带上会员等级,就像把两本病历按身份证号订在一起:号对上了,两本的内容都归这一行。

最小可用配对

import pandas as pd orders = pd.DataFrame({ '单号': ['T01', 'T02', 'T03', 'T04'], '会员号': ['M23', 'M08', 'M23', 'M99'], # M99查无此人 '金额': [1280, 960, 1732, 880], }) members = pd.DataFrame({ '会员号': ['M08', 'M23', 'M31'], # M31从没下过单 '等级': ['金卡', '银卡', '铜卡'], }) merged = orders.merge(members, on='会员号', how='inner') print(merged) # 单号 会员号 金额 等级 # 0 T01 M23 1280 银卡 # 1 T03 M23 1732 银卡 # 2 T02 M08 960 金卡

inner把两头都对不上的行全丢了:T04(脏键)和M31(沉睡会员)同时消失。这正是默认参数的危险——你什么都没感觉到,数据已经少了

四种口径,四份报告

# left:保订单视角,查无此人的交易保留,等级为NaN print(orders.merge(members, on='会员号', how='left')) # 单号 会员号 金额 等级 # 0 T01 M23 1280 银卡 # 1 T02 M08 960 金卡 # 2 T03 M23 1732 银卡 # 3 T04 M99 880 NaN ← 脏键现形 # outer:全量表,两头都保,两边都缺的补NaN both = orders.merge(members, on='会员号', how='outer', indicator=True) print(both) # 单号 会员号 金额 等级 _merge # 0 T01 M23 1280.0 银卡 both # 1 T03 M23 1732.0 银卡 both # 2 T02 M08 960.0 金卡 both # 3 T04 M99 880.0 NaN left_only ← 只在订单侧 # 4 NaN M31 NaN 铜卡 right_only ← 只在会员侧

indicator=True给每行挂来源标:both两边都有、left_only只有左表。归并后先看_merge的分布再下结论,是这章最重要的习惯——脏键、沉睡会员,一眼现形。

💡 关键直觉:left是分析主口径(以事实表订单为准),outer是盘点口径(全面清点),inner只该在有意识地"只看交集"时用。永远用默认inner又不看行数的人,迟早交出一份少了三成数据的报告。

多键、键名不同、膨胀预防

# 键名不同:left_on与right_on分别指定 a = pd.DataFrame({'店号': ['A', 'B'], '城市': ['北京', '上海']}) b = pd.DataFrame({'code': ['A', 'B'], '面积': [120, 200]}) print(a.merge(b, left_on='店号', right_on='code')) # 店号 城市 code 面积 # 0 A 北京 A 120 # 1 B 上海 B 200 # 多键:门店加月份联合配对 # orders.merge(daily, on=['门店', '月份']) # validate:连接前声明预期关系,违规直接抛错 try: orders.merge(members, on='会员号', validate='one_to_one') except pd.errors.MergeError as e: print('拦截:', e) # 拦截: Merge keys are not unique in left dataset; not a one-to-one

多对多连接是行数暴涨的第一来源:左表两行M23配右表(若有重复)两行M23,出来四行。validate写上预期的m:1或1:1,让机器替你守门。

四种口径的去留图

merge四种how的行取舍

merge四种how的行取舍

本节要点回顾

  • on指定配对键,键名不同用left_on与right_on,多键传列表
  • suffixes参数管重名列的后缀,冲突列名提前规划能省后续rename
  • 四种口径:inner交集、left保左、right保右、outer全量,选哪个是业务决定
  • indicator标来源,left_only/right_only暴露脏键与孤立记录
  • validate守门,把多对多膨胀拦在连接之前
  • 归并后核对行数:涨了跌了都要能解释

追问:归并后行数对账表

把merge的质量控制固化成习惯:任何一次归并,前后行数都要能讲出道理。三个数字必看——左表行数、右表行数、结果行数。inner结果应小于等于左表(有脏键会更少);left结果等于左表(除非右表键重复引发膨胀);outer结果大于等于两表较大者。一次实战演算:

print('左表:', len(orders), '右表:', len(members)) inner = orders.merge(members, on='会员号', how='inner') left = orders.merge(members, on='会员号', how='left') print('inner:', len(inner), 'left:', len(left)) # 左表: 4 右表: 3 # inner: 3 left: 4 # 差的那1条就是脏键M99——inner静默吞掉了它

行数对不上预期时的排查顺序:先看_merge分布定位哪侧缺,再回第04章检查键的规范化(空格、大小写、全半角),最后才考虑业务上的真孤儿记录。三个数字、两分钟,避免"报告少了三成数据没人发现"的经典事故。

下一节讲第二台器械:concat的纵向堆叠。


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