6-3 stack与unstack的床位调整


文档摘要

6-3 stack与unstack:宽长之间的床位调整 本节摘要:unstack把层次索引的某一层掀到列上变宽表,stack把列名压回索引变长表,两者是纯搬运不聚合的形态转换。本节讲清层次索引这个操作台、层号与层名的指定法、以及与第05章melt的分工边界。 归并室的收官器械。5-1的分组结果和5-3的透视表都产出过层次索引,病人躺在"多层床"上,有时要把上铺的掀下来(unstack),有时要把摊开的收回去(stack)。它和melt一样做宽长转换,区别在操作对象:stack与unstack以层次索引为舞台,melt以普通列名为舞台。 unstack:掀上铺 unstack('渠道')用层名,unstack(0)或unstack(1)用层号(0最外层)。

6-3 stack与unstack:宽长之间的床位调整

本节摘要:unstack把层次索引的某一层掀到列上变宽表,stack把列名压回索引变长表,两者是纯搬运不聚合的形态转换。本节讲清层次索引这个操作台、层号与层名的指定法、以及与第05章melt的分工边界。

归并室的收官器械。5-1的分组结果和5-3的透视表都产出过层次索引,病人躺在"多层床"上,有时要把上铺的掀下来(unstack),有时要把摊开的收回去(stack)。它和melt一样做宽长转换,区别在操作对象:stack与unstack以层次索引为舞台,melt以普通列名为舞台

unstack:掀上铺

import pandas as pd # 一张两层病床:门店-渠道双层索引的金额 s = pd.Series( [1280, 960, 1732, 880, 2100], index=pd.MultiIndex.from_product([['A', 'B', 'C'], ['线上', '线下', '']], names=['门店', '渠道'])) s = s[s.index.get_level_values('渠道') != ''] print(s) # 门店 渠道 # A 线上 1280 # 线下 960 # B 线上 1732 # C 线下 2100 ← 层次索引:数据是长形态 # unstack把内层(渠道)掀到列上 wide = s.unstack('渠道') print(wide) # 渠道 线上 线下 # 门店 # A 1280 960.0 # B 1732 NaN # C NaN 2100.0

unstack('渠道')用层名,unstack(0)或unstack(1)用层号(0最外层)。掀床的结果:行变少、列变多、没数据的格子自动补NaN。

stack:收摊

# stack是逆操作:把列名压回索引层 long = wide.stack() print(long) # 门店 渠道 # A 线下 960.0 # 线上 1280.0 # B 线上 1732.0 # C 线下 2100.0 # 注意两个细节: # 一、stack默认丢弃NaN格(dropna=True),A线上B线下那种空格直接消失 # 二、值列因NaN的存在已是float,来回转换后dtype不还原 filled = wide.fillna(0).stack() print(filled) # A 线下 960.0 # 线上 1280.0 # B 线上 1732.0 # 线下 0.0 ← 0补位后保留 # C 线下 2100.0 # 线上 0.0

⚠️ 常见坑:stack默认悄悄丢掉NaN格子,且不发任何提示。想要"每个组合都占一格"的完整长表,先fillna再stack;反过来,想保持稀疏(没开张就是没记录),就利用这个默认行为。

DataFrame的双向调整

df = pd.DataFrame({ '门店': ['A', 'A', 'B', 'B'], '渠道': ['线上', '线下', '线上', '线下'], '金额': [1280, 960, 1732, 880], }) pivot = df.pivot_table(index='门店', columns='渠道', values='金额', aggfunc='sum') # 层次索引版的长表:索引是门店-渠道两层 hi = pivot.stack().rename('金额').reset_index() print(hi) # 门店 渠道 金额 # 0 A 线下 960.0 # 1 A 线上 1280.0 # 2 B 线上 1732.0 # 3 B 线下 880.0 # 列也可以是多层的:unstack两次得到二维排版 multi = df.pivot_table(index='门店', columns='渠道', values='金额', aggfunc='sum') swapped = multi.T # 行列互换的快捷方式 print(swapped.index.name) # 渠道

stack与melt的分工边界

宽长转换的两条路

维度 stack与unstack melt
操作台 层次索引 普通列名
聚合 无,纯搬运 无,纯搬运
典型入口 分组或透视的产物 人手维护的宽报表
NaN行为 stack默认丢弃 保留为行
配套出口 unstack pivot_table

06-6-fig01-6

本节要点回顾

  • unstack掀层变宽,按层名或层号指定,空格补NaN
  • stack压列回长,默认丢NaN格,完整格子先fillna
  • 来回转换dtype可能变float,严谨场景转回后再astype
  • 与melt的分界:入口是层次索引用stack,普通宽表用melt
  • T是行列快翻,简单场景比unstack省事

追问:什么场景真的需要宽长转换

床铺调整不是炫技,三类真实需求撑起它的出场率。其一,人看的对比表天然是宽的(门店对比渠道),机器吃的建模表天然是长的(每行一个观测),一份分析常常两头都要。其二,多指标相关性分析:各渠道金额在宽形态下才能一句corr算出相关矩阵。其三,入库与出库:数据库范式偏爱长形态,报表平台偏爱宽形态,ETL的中段就是在两种形态间来回摆渡。

# 宽形态的corr:一句话看出渠道间的联动 wide2 = df.pivot_table(index='门店', columns='渠道', values='金额', aggfunc='sum') print(wide2.corr().round(2)) # 渠道 线上 线下 # 渠道 # 线上 1.00 NaN # 样本太小,相关系数无意义,仅示意流程 # 线下 NaN 1.00

样本量放大后这张表才有诊断价值,但管道就是这两行。工具的意义在于规模变化时管道不用重写。

归并室收工清单

三台器械各自的验收点:merge——口径想清楚、indicator看了、行数对上了;concat——索引处理决定了、结构差异是个决定而不是意外;stack与unstack——NaN的丢弃与保留是知情选择。归并室输出的宽表,就是下一章时间轴要接手的病史正本。

归并室收工。下一章给病史装上时间轴,进入长期随访。


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