Pandas DataFrame多列堆叠与重塑技巧

聖光之護
发布: 2025-11-18 14:18:07
原创
591人浏览过

Pandas DataFrame多列堆叠与重塑技巧

本文将深入探讨在pandas dataframe中将多对相关列(如`right_count`, `right_sum`, `left_count`, `left_sum`)高效重塑为更紧凑长格式(如`side`, `count`, `sum`)的多种方法。我们将介绍基于multiindex和`stack`的自定义重塑、结合`melt`和`pivot`的经典方案,以及利用`janitor`库中`pivot_longer`函数的简洁实现,旨在提供清晰、专业的教程,帮助读者根据具体场景选择最合适的重塑策略。

在数据分析和处理中,我们经常需要将宽格式(wide format)的DataFrame转换为长格式(long format),以便于后续的聚合分析或可视化。特别是当多组相关数据分散在多个列中时,例如本例中的right_count, right_sum和left_count, left_sum,将其重塑为包含“侧边”(side)、“计数”(count)和“总和”(sum)等新列的长格式,能显著提高数据的可读性和可用性。

示例数据准备

首先,我们定义一个初始的Pandas DataFrame,它包含日期、其他列以及左右两侧的计数和总和数据:

import pandas as pd

df = pd.DataFrame({
    'date': ['2023-12-01', '2023-12-05', '2023-12-07'],
    'other_col': ['a', 'b', 'c'],
    'right_count': [4, 7, 9],
    'right_sum': [2, 3, 5],
    'left_count': [1, 8, 5],
    'left_sum': [0, 8, 4]
})

print("原始 DataFrame:")
print(df)
登录后复制

我们的目标是将right_count, right_sum, left_count, left_sum这四列重塑为side、count和sum三列,同时保留date和other_col作为标识符。

方法一:利用MultiIndex和stack进行自定义重塑

这种方法通过巧妙地创建多级列索引(MultiIndex),然后使用stack操作将特定级别的索引转换为新的行,从而实现数据的重塑。

# 方法一:利用MultiIndex和stack进行自定义重塑
out_multiindex = (df
                  .set_index(['date', 'other_col']) # 将不变的列设为索引
                  # 将列名 'side_value' (如 'right_count') 拆分为多级索引 ('side', 'value')
                  .pipe(lambda x: x.set_axis(x.columns.str.split('_', expand=True), axis=1))
                  .rename_axis(columns=['side', None]) # 命名多级索引的级别,'side' 为第一个级别,第二个级别不命名
                  .stack('side') # 堆叠 'side' 级别的索引,将其转换为行
                  .reset_index() # 将所有索引(包括新生成的 'side')转换回普通列
                 )

print("\n方法一结果 (MultiIndex + stack):")
print(out_multiindex)
登录后复制

解析:

  1. set_index(['date', 'other_col']): 将date和other_col设置为DataFrame的索引,这些列在重塑过程中将保持不变。
  2. pipe(lambda x: x.set_axis(x.columns.str.split('_', expand=True), axis=1)): 这是一个关键步骤。它将原始的列名(如right_count)通过下划线_分割,并使用expand=True创建一个新的MultiIndex作为列索引。例如,right_count会变成('right', 'count')。
  3. rename_axis(columns=['side', None]): 命名新创建的多级列索引的级别。第一个级别被命名为'side',第二个级别(如count或sum)保持匿名(None)。
  4. stack('side'): 这是重塑的核心。它将名为'side'的列索引级别从列堆叠到行中,从而将宽格式数据转换为长格式。
  5. reset_index(): 将所有索引(包括原始的date, other_col以及新生成的side)转换回普通的列,并清除可能由stack操作产生的额外索引名称。

方法二:结合melt和pivot实现重塑

这种方法是Pandas中处理宽长格式转换的经典组合,通过melt操作将多列“融化”为两列(变量名和值),然后通过字符串处理提取信息,最后使用pivot进行重塑。

# 方法二:结合melt和pivot实现重塑
tmp = df.melt(['date', 'other_col'], var_name='temp_col') # 先融化所有需要重塑的列
# 从新的列名 'temp_col' 中拆分出 'side' 和 'col' (如 'count' 或 'sum')
tmp[['side', 'col']] = tmp['temp_col'].str.split('_', n=1, expand=True)

out_melt_pivot = (tmp.pivot(index=['date', 'other_col', 'side'], # 设置新的行索引
                            columns='col', values='value') # 根据 'col' 进行透视,将 'value' 填充
                  .reset_index() # 将索引转换回列
                  .rename_axis(columns=None) # 清除透视产生的列名索引(默认为 'col')
                 )

print("\n方法二结果 (melt + pivot):")
print(out_melt_pivot)
登录后复制

解析:

  1. df.melt(['date', 'other_col'], var_name='temp_col'): melt函数用于将DataFrame从宽格式转换为长格式。id_vars参数指定了不进行重塑的标识符列。所有其他列将被“融化”:它们的列名将放入var_name指定的新列(此处为temp_col),而它们的值将放入value列。
  2. tmp[['side', 'col']] = tmp['temp_col'].str.split('_', n=1, expand=True): melt操作后,temp_col列包含了原始的列名(如right_count)。我们利用字符串的split('_', n=1, expand=True)方法,将其拆分为两部分:side(如right或left)和col(如count或sum)。
  3. tmp.pivot(index=['date', 'other_col', 'side'], columns='col', values='value'): pivot函数用于将长格式数据重新透视回宽格式,但这次是按照我们新的需求。index指定了新的行索引,columns指定了将作为新列的列,values指定了填充新列的值。
  4. reset_index().rename_axis(columns=None): reset_index将透视操作产生的索引转换回列。rename_axis(columns=None)则用于清除pivot操作可能在列索引上留下的名称(例如,col)。

方法三:使用janitor库的pivot_longer简化操作

janitor是一个提供简洁、易用数据清理和转换函数的Python库。它的pivot_longer函数专门用于处理这种将多列重塑为长格式的场景,尤其当列名具有特定模式时,它能极大地简化代码。

降重鸟
降重鸟

要想效果好,就用降重鸟。AI改写智能降低AIGC率和重复率。

降重鸟 113
查看详情 降重鸟
# 方法三:使用janitor库的pivot_longer简化操作
# 如果尚未安装,请先执行:pip install pyjanitor
import janitor

out_janitor = df.pivot_longer(index=['date', 'other_col'],
                              names_to=('side', '.value'), # 指定新的列名,.value 是一个特殊关键字
                              names_pattern=r'([^_]+)_([^_]+)') # 正则表达式匹配 'side_value' 模式

print("\n方法三结果 (janitor.pivot_longer):")
print(out_janitor)
登录后复制

解析:

  1. import janitor: 导入janitor库。
  2. df.pivot_longer(index=['date', 'other_col'], ...): pivot_longer是janitor提供的函数,index参数与melt类似,指定了不进行重塑的标识符列。
  3. names_to=('side', '.value'): 这是一个关键参数。它告诉pivot_longer如何命名新生成的列。'side'将作为新列的名称,而.value是一个特殊占位符,表示从原始列名中提取的值将作为新的列(例如count和sum)。
  4. names_pattern=r'([^_]+)_([^_]+)': 这是一个正则表达式,用于从原始列名中捕获模式。([^_]+)匹配一个或多个非下划线字符。第一个捕获组将对应names_to中的第一个元素(side),第二个捕获组将对应.value所代表的列(count和sum)。

总结与注意事项

以上三种方法都能实现将多列堆叠重塑为新列的目标,但它们各有特点和适用场景:

  • 方法一(MultiIndex + stack)

    • 优点:高度灵活,能够处理复杂的层级重塑,是Pandas底层机制的体现。
    • 缺点:代码相对复杂,需要对Pandas的MultiIndex有较深入的理解。
    • 适用场景:当你需要对列进行多级分组,并根据这些级别进行堆叠时。
  • 方法二(melt + pivot)

    • 优点:使用Pandas内置函数,不引入额外依赖;逻辑清晰,分步执行,易于理解和调试。
    • 缺点:相比pivot_longer,步骤稍多。
    • 适用场景:不想引入第三方库,且对Pandas的melt和pivot操作熟悉,或当列名模式不完全规整,需要更多中间处理时。
  • 方法三(janitor.pivot_longer)

    • 优点:代码最简洁、直观,特别适合列名有清晰模式(如prefix_suffix)的场景,大大提高了开发效率。
    • 缺点:需要安装并引入第三方库janitor。
    • 适用场景:追求代码简洁性、可读性,且列名模式规整时,是首选方案。

在选择具体方法时,应综合考虑项目的依赖管理、团队成员的熟悉程度以及重塑任务的复杂性。对于日常的数据清洗和转换,janitor.pivot_longer无疑是一个非常强大的工具。如果项目不允许额外依赖,或者需要更精细的控制,melt与pivot的组合是稳健的选择。而基于MultiIndex的stack方法,则为处理更底层、更复杂的DataFrame结构提供了最大的灵活性。

以上就是Pandas DataFrame多列堆叠与重塑技巧的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号