Pandas DataFrame:优化多列批量加减运算

心靈之曲
发布: 2025-11-23 12:56:16
原创
832人浏览过

Pandas DataFrame:优化多列批量加减运算

本教程详细介绍了在pandas dataframe中对多列执行批量加减运算的两种高效方法。我们将探讨如何利用`dataframe.eval()`进行多行表达式求值,以及如何通过链式调用`add()`和`sub()`方法结合向量化操作实现相同效果。文章将提供详细的代码示例和解释,帮助读者根据具体场景选择最合适的策略,从而提升数据处理效率和代码可读性

引言:DataFrame多列批量运算挑战

在数据分析和处理中,我们经常需要对Pandas DataFrame中的多个列执行相同的算术运算。例如,可能需要将某个基准列的值从一组目标列中减去,然后再加上另一个参考列的值。手动逐列编写这样的操作(如 df['C'] = df['C'] - df['B'] + df['A'],然后对 D 和 E 重复)不仅冗长,而且效率低下,尤其当涉及的列数很多时。本教程将介绍两种更优雅、更高效的解决方案,帮助您简化代码并提升性能。

方法一:使用 DataFrame.eval() 实现多行表达式求值

DataFrame.eval() 方法允许您使用字符串表达式对DataFrame进行计算,其语法更接近数学表达式,并且可以处理多行表达式,从而实现对多列的批量操作。对于复杂的、涉及多个列的运算,eval() 提供了一种简洁且可读性强的解决方案。

示例代码

假设我们有一个DataFrame df,需要将列 C, D, E 分别减去 B 列的值,然后加上 A 列的值。

import pandas as pd

data = {
  "A": [42, 38, 39, 23],
  "B": [45, 30, 15, 65],
  "C": [60, 50, 25, 43],
  "D": [12, 70, 35, 76],
  "E": [87, 90, 45, 43],
  "F": [40, 48, 55, 76],
  "G": [58, 42, 85, 10],
}
df = pd.DataFrame(data)

print("原始DataFrame:")
print(df)

# 使用eval()进行批量操作
df_eval = df.copy() # 创建副本以避免修改原始DataFrame
df_eval = df_eval.eval('''C = C - B + A
D = D - B + A
E = E - B + A
''')

print("\n使用eval()后的DataFrame:")
print(df_eval)
登录后复制

解释

eval() 方法接受一个多行字符串作为参数,其中每一行代表一个赋值表达式。在表达式中,您可以直接引用DataFrame的列名,eval() 会自动识别并将其视为Series对象进行计算。这种方法在内部利用NumExpr库进行优化,对于大型数据集可以提供显著的性能提升。它将多个独立的赋值操作合并为一个高效的内部计算过程。

方法二:利用链式 add() 和 sub() 进行向量化操作

Pandas的Series和DataFrame对象支持向量化操作,这意味着您可以对整个列或DataFrame执行算术运算,而无需编写显式的循环。通过链式调用 add() 和 sub() 等方法,我们可以构建出高效且表达力强的批量操作。这种方法特别适用于当多个目标列需要应用相同的偏移量或变换时。

微撰
微撰

AI智能写作平台

微撰 207
查看详情 微撰

示例代码

我们将使用与上述相同的数据集,通过链式方法实现相同的运算。

import pandas as pd

data = {
  "A": [42, 38, 39, 23],
  "B": [45, 30, 15, 65],
  "C": [60, 50, 25, 43],
  "D": [12, 70, 35, 76],
  "E": [87, 90, 45, 43],
  "F": [40, 48, 55, 76],
  "G": [58, 42, 85, 10],
}
df = pd.DataFrame(data)

# print("原始DataFrame:") # 原始DataFrame已在eval示例中打印
# print(df)

# 使用链式add/sub进行批量操作
df_chained = df.copy() # 创建副本以避免修改原始DataFrame

# 计算共同的偏移量:A - B
# df['A'].sub(df['B']) 等同于 df['A'] - df['B']
offset = df_chained['A'].sub(df_chained['B'])

# 将偏移量加到目标列上
# df[['C', 'D', 'E']] 是一个包含目标列的子DataFrame
# .add(offset, axis=0) 将 Series 'offset' 按行(axis=0)广播到子DataFrame的每一列
df_chained[['C', 'D', 'E']] = df_chained[['C', 'D', 'E']].add(offset, axis=0)

print("\n使用链式add/sub后的DataFrame:")
print(df_chained)
登录后复制

解释

这种方法的核心在于利用Pandas的广播机制。首先,我们计算出所有目标列都需要共享的共同偏移量 A - B,这会得到一个Series对象 offset。然后,我们选择目标列 df_chained[['C', 'D', 'E']],并使用 .add() 方法将 offset Series 添加到这些列上。axis=0 参数确保 offset Series 的值按行与目标DataFrame的每一列对齐并相加。这种方式非常直观,且充分利用了Pandas底层的优化,提供了出色的性能。

两种方法的比较与选择

  • DataFrame.eval():
    • 优点: 语法简洁,更接近自然语言或数学表达式,尤其适合处理多行且逻辑复杂的表达式。对于大型DataFrame,它通常能提供更好的性能,因为它利用NumExpr库进行优化。
    • 缺点: 字符串表达式可能在某些情况下难以调试。此外,应避免在eval()中使用不受信任的用户输入,以防潜在的安全风险。
  • 链式 add()/sub():
    • 优点: 代码更具Pandas风格,显式调用方法使得操作流程清晰。对于本例中这种“对多列应用相同操作”的场景,通过计算一个公共偏移量并进行广播,代码简洁高效。易于理解其向量化原理。
    • 缺点: 对于非常复杂的、涉及不同运算逻辑的多列操作,可能需要更复杂的链式调用或分步操作。

性能考量: 对于大多数常见的数据集大小,这两种方法都比传统的Python循环快得多。在极大规模的数据集上,eval() 可能会因其底层的NumExpr优化而略胜一筹。然而,在实际应用中,选择哪种方法更多取决于代码的可读性、维护性以及个人或团队的偏好。

总结

Pandas为DataFrame中的批量算术运算提供了多种高效且灵活的工具。DataFrame.eval() 提供了一种简洁的字符串表达式方式,适用于复杂的多行逻辑。而链式调用 add() 和 sub() 等方法则通过向量化和广播机制,为重复的、结构化的运算提供了清晰高效的解决方案。掌握这两种方法,将使您能够更有效地处理数据,编写出更简洁、更专业的Pandas代码。在实际工作中,建议根据具体任务的复杂性、代码的可读性要求以及性能需求来选择最适合的方法。

以上就是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号