如何在Pandas中按原列序透视DataFrame并保留重复值行
问题:DataFrame透视时保持列顺序并按分组重复值换行
原始DataFrame
import pandas as pd data = { 'Type': ['Z', 'x', 'A', 'A', 'A', 'D', 'B', 'B','Z', 'x', 'A', 'A', 'A', 'D', 'B', 'B'], 'Val': ['012', '11', '123', '567', '101', '22', 'T54', '111','012', '11', '123', '500', '101', '22', 'T54', '111'] } df = pd.DataFrame(data)
需求
对上述DataFrame执行透视操作,需满足:
- 保持列的原始顺序(即Z、x、A、D、B)
- 同一
Type对应的多个Val值依次添加到新行,期望输出如下:
| Z | x | A | D | B |
|---|---|---|---|---|
| 012 | 11 | 123 | 22 | T54 |
| nan | nan | 567 | nan | 111 |
| nan | nan | 101 | nan | nan |
| 012 | 11 | 123 | 22 | T54 |
| nan | nan | 500 | nan | 111 |
| nan | nan | 101 | nan | nan |
尝试的代码(未得到期望输出)
df['Type'] = pd.Categorical(df['Type'], categories=df['Type'].unique(), ordered=True) df['Row'] = df.groupby('Type').cumcount() df = df.pivot(index='Row', columns='Type', values='Val') df = df.reset_index(drop=True) df.columns.name = None
这段代码的问题在于:全局按Type分组累计计数,会把原始数据中两组重复的Type序列合并到同一行,无法区分前8行和后8行的独立块。
解决方案
先识别原始数据中的重复序列块,给每个块分配独立ID,再结合块内的Type累计计数生成行索引,代码如下:
import pandas as pd data = { 'Type': ['Z', 'x', 'A', 'A', 'A', 'D', 'B', 'B','Z', 'x', 'A', 'A', 'A', 'D', 'B', 'B'], 'Val': ['012', '11', '123', '567', '101', '22', 'T54', '111','012', '11', '123', '500', '101', '22', 'T54', '111'] } df = pd.DataFrame(data) # 标记重复序列块:当Type等于第一个元素时,视为新块的起始 df['Block'] = (df['Type'] == df['Type'].iloc[0]).cumsum() # 按块和Type分组,计算每个Type在块内的累计行数 df['Row'] = df.groupby(['Block', 'Type']).cumcount() # 设置分类类型,保持列的原始顺序 unique_types = df['Type'].unique() df['Type'] = pd.Categorical(df['Type'], categories=unique_types, ordered=True) # 透视并整理结果 result = df.pivot(index=['Block', 'Row'], columns='Type', values='Val') result = result.reset_index(drop=True) result.columns.name = None print(result)
代码说明
- 标记块ID:通过判断当前行
Type是否等于序列第一个元素(Z),累计得到块ID,将原始数据拆分为两个独立的块。 - 块内累计计数:按块和
Type分组后累计计数,确保每个块内的Type重复值生成独立的行索引。 - 透视整理:以
(Block, Row)作为联合索引执行透视,最后重置索引得到期望格式。
内容的提问来源于stack exchange,提问作者educational board
相关产品推荐
相关产品推荐

