在Pandas的数据处理场景中,apply函数是灵活处理行或列数据的常用工具,当我们需要对多个指定列做相同逻辑的处理时,手动逐个传入列名会非常繁琐,通过列名列表批量传递多列参数可以有效解决这个问题。

apply函数的基本使用逻辑
apply函数可以作用于DataFrame的行或列,默认按列处理,通过axis参数可以控制处理方向,axis=1表示按行处理,此时传递给处理函数的会是每一行的数据,我们可以通过列名来获取对应列的值。
首先我们先创建一个测试用的DataFrame,后续示例都基于这个数据:
import pandas as pd
# 创建测试DataFrame
data = {
"math": [90, 85, 78, 92],
"chinese": [88, 92, 85, 90],
"english": [76, 89, 91, 87],
"name": ["张三", "李四", "王五", "赵六"]
}
df = pd.DataFrame(data)
print(df)
方案一:按行处理时直接传入列名列表
当我们需要按行处理多个列的数据时,可以先定义需要处理的列名列表,然后在apply的处理函数中通过列名列表批量获取对应列的值,这种方式适合需要对多个列做相同运算的场景。
比如我们需要计算math、chinese、english三科的总分,就可以用这种方式实现:
# 定义需要处理的列名列表
score_columns = ["math", "chinese", "english"]
# 定义处理函数,row是每一行的数据,通过列名列表批量获取值
def calc_total_score(row):
# 用列表推导式批量获取所有目标列的值并求和
total = sum([row[col] for col in score_columns])
return total
# 按行处理,axis=1
df["total_score"] = df.apply(calc_total_score, axis=1)
print(df)
这种方式的优势是逻辑清晰,处理函数内部可以灵活调整对每个列的处理逻辑,如果不同列需要不同的处理规则也可以很方便地修改。
方案二:通过双括号传入多列构建子DataFrame
除了按行处理的方式,我们还可以通过DataFrame的双括号语法,直接传入列名列表获取对应的多列子DataFrame,然后将这个子DataFrame传递给apply函数处理,这种方式不需要设置axis参数,默认按列处理子DataFrame。
同样以计算三科总分为例,实现方式如下:
# 定义需要处理的列名列表 score_columns = ["math", "chinese", "english"] # 直接传入列名列表获取子DataFrame,然后调用apply计算每行的和 # apply的参数是sum,会对子DataFrame的每一行求和 df["total_score"] = df[score_columns].apply(sum, axis=1) print(df)
这种方式代码更简洁,适合处理逻辑比较简单,只需要对多列做统一的聚合运算的场景,不需要额外定义处理函数。
两种方案的对比和适用场景
| 方案 | 优势 | 适用场景 |
|---|---|---|
| 按行处理传入列名列表 | 处理逻辑灵活,可自定义不同列的处理规则 | 需要对多列做复杂逻辑处理,不同列处理规则有差异的情况 |
| 双括号传入多列子DataFrame | 代码简洁,无需额外定义函数 | 处理逻辑简单,只需要对多列做统一聚合运算的情况 |
注意事项
- 列名列表中的列名必须存在于DataFrame中,否则会抛出KeyError错误
- 按行处理时必须要设置axis=1,否则apply会默认按列处理,导致获取不到对应的值
- 如果列名包含特殊字符或者空格,需要用英文下划线_替换空格后使用,或者在列名列表中用字符串形式正确书写列名
如果需要处理的列是连续的,也可以使用df.iloc[:, start_col:end_col]的方式获取列范围,再传递给apply函数,不需要手动列出所有列名。