本节前言

函数应用是将自定义逻辑批量作用于数据的核心机制。本节覆盖元素级(map)、行 / 列级(apply、applymap)、管道(pipe)以及聚合 / 变换(agg、transform、eval、query)。

1. map()

Series 专用,对每个元素应用函数或字典映射,返回新 Series。

s = pd.Series([1, 2, 3])
 
# 函数映射
s.map(lambda x: x * 10)
# 0    10
# 1    20
# 2    30
 
# 字典映射
s.map({1: 'one', 2: 'two', 3: 'three'})
# 0     one
# 1     two
# 2     three

map 与 replace 区别

  • map 遇到字典中不存在的键返回 NaN。
  • replace 保留不匹配的原始值。
  • pandas 2.1+ 中 DataFrame.map() 取代了 DataFrame.applymap(),但 Series.map() 语义保持不变。

2. apply()

Series / DataFrame 通用。

  • Series:对每个元素应用函数(与 map 类似)。
  • DataFrame:沿 axis 对每行或每列应用函数。
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
 
# DataFrame:默认对每列(axis=0)应用
df.apply(lambda col: col.sum())
# A    3
# B    7
 
# 对每行应用
df.apply(lambda row: row.sum(), axis=1)
# 0    4
# 1    6
 
# 返回多个值
df.apply(lambda col: (col.min(), col.max()))

apply 的性能警告

apply 是 Python 循环的封装,并非真正的向量化。性能敏感场景应尽量使用向量化操作或 agg / transform。

3. applymap()

DataFrame 专用,对 DataFrame 的每个元素逐一遍历应用函数。

df.applymap(lambda x: x * 2)
#    A  B
# 0  2  6
# 1  4  8

pandas 2.1 变更

  • DataFrame.applymap() 在 pandas 2.1 中已被弃用,推荐使用 DataFrame.map()。
  • 新代码建议使用 df.map()。
  • 注意 Series.map() 与 DataFrame.map() 语义不同。

4. pipe()

函数管道调用,将前面的对象作为第一个参数传入函数,适合链式操作。

def add_one(df):
    return df + 1
 
def multiply(df, factor):
    return df * factor
 
# 传统写法
multiply(add_one(df), 3)
 
# pipe 写法
df.pipe(add_one).pipe(multiply, factor=3)
 
# 也支持 (func, kwargs) 元组
df.pipe((multiply, 'factor'), 3)
方式写法
普通调用func(df, *args, **kwargs)
pipe 调用df.pipe(func, *args, **kwargs)

pipe 的价值

  • 让代码从左到右阅读,减少嵌套。
  • 便于复用数据清洗流水线。

5. agg() / aggregate()

对 Series / DataFrame 执行一个或多个聚合操作,返回标量汇总结果。

df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
 
# 单一聚合
df.agg('sum')
# A     6
# B    15
 
# 多个聚合
df.agg(['sum', 'mean', 'max'])
#        A    B
# sum    6   15
# mean   2    5
# max    3    6
 
# 每列不同聚合
df.agg({'A': 'sum', 'B': ['mean', 'std']})
 
# 自定义函数
df.agg(lambda x: x.max() - x.min())

aggregate 与 agg 完全等价,是同一个方法的别名。

6. transform()

对数据执行函数并返回与输入相同形状的结果。

df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
 
# 标准化(每列)
df.transform(lambda x: (x - x.mean()) / x.std())
 
# 多个变换
df.transform(['sqrt', 'abs'])
 
# 每列不同变换
df.transform({'A': 'sqrt', 'B': 'abs'})
方法返回形状用途
agg()标量汇总统计摘要
transform()原始形状逐元素变换、标准化
apply()灵活通用函数应用

与 groupby 的关系

GroupBy.agg() 和 GroupBy.transform() 是分组聚合的核心方法,详见 十六、分组与聚合(如大纲扩展笔记)。

7. eval()

使用字符串表达式进行向量化计算。

df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
 
# DataFrame.eval()
df.eval('C = A + B')
#    A  B  C
# 0  1  3  4
# 1  2  4  6
 
# 局部变量
df.eval('C = A + @factor', local_dict={'factor': 10})
 
# pd.eval():通用表达式
pd.eval('A + B', local_dict={'A': df['A'], 'B': df['B']})

性能优势

eval() 避免创建中间 Python 对象,在大 DataFrame 上性能优于普通表达式。

8. query()

使用字符串表达式筛选 DataFrame 的行。

df = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]})
 
df.query('A > 1')
#    A  B
# 1  2  5
# 2  3  6
 
# 多条件
df.query('A > 1 and B < 6')
 
# 引用外部变量
threshold = 2
df.query('A > @threshold')
 
# 列名含空格
df.query('`my col` > 1')

query 与布尔索引

df.query('A > 1') 等价于 df[df['A'] > 1],但更简洁、更贴近 SQL 习惯。

🔗 相关笔记