在Pandas DataFrame中为每行应用不同的可调用函数

DDD
发布: 2025-10-20 10:06:01
原创
645人浏览过

在pandas dataframe中为每行应用不同的可调用函数

本文探讨了如何在Pandas DataFrame中为每行应用不同的可调用函数,解决了当计算逻辑依赖于行特定参数(包括函数本身)时的挑战。通过结合相关数据框,并利用`DataFrame.apply()`方法与一个接收整行作为参数的辅助函数,可以优雅且高效地实现这一需求,避免了低效的列表推导式。

在数据分析和处理中,我们经常需要对Pandas DataFrame中的数据执行操作。通常,这些操作是向量化的,即对整列应用相同的函数。然而,在某些复杂场景下,每行的计算逻辑可能不同,甚至需要应用不同的函数。例如,一个DataFrame包含输入数据,另一个包含计算参数,而第三个DataFrame则指定了每行应使用的具体函数。如何优雅地处理这种“行级函数分派”是Pandas用户面临的一个常见问题

场景描述与初始方法

假设我们有三个DataFrame:input_df 包含待处理的原始数据,param_df 包含计算所需的参数,而 param_df 中还额外包含了一列,指定了对每行数据进行操作的具体函数。我们的目标是根据 param_df 中指定的函数和参数,计算并填充 output_df。

考虑以下示例:

import pandas as pd
import numpy as np

# 定义两个不同的函数
def func_1(in_val, a, b):
    return in_val + a + b

def func_2(in_val, a, b):
    return in_val + (2 * (a + b))

# 准备输入数据
input_df = pd.DataFrame(data=[1 for row in range(10)],
                        columns=["GR"])

# 准备输出DataFrame,初始为空
output_df = pd.DataFrame(data=[np.nan for row in range(10)],
                         columns=["VCLGR"])

# 准备参数DataFrame,包含计算所需的参数
param_df = pd.DataFrame(data=[[5, 10] for row in range(10)],
                        columns=["x", "y"])

# 向参数DataFrame中添加可调用函数,前5行使用func_1,后5行使用func_2
param_df["method"] = func_1
param_df.loc[5:, "method"] = func_2

print("Input DataFrame (input_df):\n", input_df)
print("\nParameter DataFrame (param_df):\n", param_df)
登录后复制

在这个场景中,一个直观但不够“Pandas风格”的解决方案是使用列表推导式:

# 使用列表推导式计算输出
output_df["VCLGR_list_comp"] = [param_df["method"][i](input_df["GR"][i], param_df["x"][i], param_df["y"][i])
                                for i in range(len(input_df))]
print("\nOutput DataFrame (using list comprehension):\n", output_df)
登录后复制

虽然列表推导式可以实现功能,但它打破了Pandas的向量化操作范式,对于大型数据集而言,可能效率较低且代码可读性不佳。我们寻求一种更符合Pandas哲学的方法。

优化方案:结合 apply 和辅助函数

Pandas提供了 DataFrame.apply() 方法,它可以在DataFrame的行或列上应用一个函数。当 axis=1 时,apply 会将DataFrame的每一行作为Series传递给指定的函数。这为我们解决上述问题提供了思路:

AppMall应用商店
AppMall应用商店

AI应用商店,提供即时交付、按需付费的人工智能应用服务

AppMall应用商店 56
查看详情 AppMall应用商店
  1. 合并相关数据: 将 input_df 和 param_df 合并成一个临时的DataFrame。这样,每一行都将包含执行计算所需的所有信息:输入值、参数以及要应用的函数本身。
  2. 定义辅助函数: 创建一个辅助函数,该函数接收一个DataFrame行(即一个Series)作为参数。在这个函数内部,我们可以通过行索引访问到该行对应的输入值、参数和可调用函数,然后执行计算。
  3. 应用辅助函数: 使用 apply(axis=1) 将辅助函数应用到合并后的DataFrame上。

下面是具体的实现:

# 1. 定义一个辅助函数,它接收一整行数据作为输入
def indirect_callable_executor(row):
  """
  根据行中的'method'、'GR'、'x'和'y'字段执行相应的计算。
  """
  return row['method'](row['GR'], row['x'], row['y'])

# 2. 合并input_df和param_df,使每行包含所有必要信息
# axis=1 表示按列合并
combined_df = pd.concat([param_df, input_df], axis=1)

# 3. 使用apply(axis=1)将辅助函数应用到合并后的DataFrame的每一行
output_df["VCLGR_apply"] = combined_df.apply(indirect_callable_executor, axis=1)

print("\nCombined DataFrame for apply:\n", combined_df)
print("\nOutput DataFrame (using apply):\n", output_df)
登录后复制

代码解析与优势

  • indirect_callable_executor(row) 函数:

    • 这个函数是解决方案的核心。当 apply(axis=1) 被调用时,combined_df 的每一行都会被转换为一个Pandas Series对象,并作为 row 参数传递给 indirect_callable_executor。
    • 在函数内部,我们可以像访问字典一样,通过列名(例如 row['method'], row['GR'], row['x'], row['y'])来获取当前行的数据。
    • row['method'] 直接返回了存储在该行中的函数对象(func_1 或 func_2),然后我们可以直接调用它并传入相应的参数。
  • pd.concat([param_df, input_df], axis=1):

    • 这一步至关重要。它将 param_df 和 input_df 水平拼接起来,创建了一个新的DataFrame combined_df。
    • 现在,combined_df 的每一行都包含了执行当前行计算所需的所有元素:输入值 (GR)、参数 (x, y) 和指定要使用的函数 (method)。这为 apply 方法提供了完整的上下文。
  • combined_df.apply(indirect_callable_executor, axis=1):

    • apply 方法遍历 combined_df 的每一行。
    • axis=1 参数指示 apply 将每一行作为一个Series传递给 indirect_callable_executor 函数。
    • indirect_callable_executor 对每行执行计算并返回结果,apply 将这些结果收集起来,形成一个新的Series,最终赋值给 output_df["VCLGR_apply"]。

这种方法的优势包括:

  • Pandas风格: 相比于列表推导式,这种方法更符合Pandas的数据处理范式,代码更具表达力。
  • 可读性: 将逻辑封装在辅助函数中,使得代码结构更清晰,易于理解和维护。
  • 灵活性: 辅助函数可以包含任意复杂的逻辑,只要它能接收一行数据并返回一个结果。
  • 潜在性能提升: 尽管 apply 在底层仍然是一个Python循环,但Pandas的内部优化通常使其比纯Python列表推导式在处理DataFrame时表现更好,尤其是在函数内部的操作能够利用Pandas/NumPy的优化时。

注意事项

  • 性能考量: 尽管优于纯Python循环,但对于极大规模的数据集,apply 仍然不是最快的选择。如果可能,始终优先考虑完全向量化的操作(例如直接使用NumPy函数或Pandas的内置方法)。然而,当每行的函数本身不同时,apply 往往是兼顾性能和灵活性的最佳原生Pandas方案。
  • 列名匹配: 确保辅助函数中引用的列名(如 GR, x, y, method)与合并后DataFrame的列名准确匹配。
  • 函数签名: 存储在DataFrame中的可调用函数的签名(参数数量和类型)必须与辅助函数中调用它时传递的参数匹配。

总结

当需要在Pandas DataFrame的每行应用不同的可调用函数时,通过将所有相关数据(包括函数本身)合并到一个DataFrame中,并结合 DataFrame.apply(axis=1) 和一个接收行数据的辅助函数,可以构建一个优雅、灵活且高效的解决方案。这种方法不仅提升了代码的可读性和可维护性,也更好地融入了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号