简单来说:map是Series的专属工具,擅长字典映射;apply更灵活,能处理Series或DataFrame,但行为取决于axis参数;applymap则只针对DataFrame,逐元素操作。

map:Series的专属映射利器
当你有单列数据需要按规则做映射替换时,比如把数字1变成“东”、2变成“南”,map就是最直接的工具。它只接受Series,不处理DataFrame。传入字典时,它会自动进行key查找,但要求类型严格匹配——df["toward"].map({1: "东"})对字符串类型的"1"会失效,要么写成{"1": "东"},要么先做类型转换。
常见的坑是什么?KeyError或者返回全NaN,多半是key类型不匹配,或者数据里混入了空值没处理。
- 遇到缺失值时,
map默认返回NaN,加上na_action="ignore"参数可以跳过 - 无法传递额外参数,函数只能接收单个元素,比如
lambda x: x.strip() - 不支持多列操作,如果要对多列做映射,要么循环处理,要么改用
replace
apply:灵活但需谨慎的通用工具
apply在Series上表现类似map,也是逐元素调用;但在DataFrame上,情况就不同了。默认情况下(axis=0),它会把整列作为一个Series传给函数。如果设置axis=1,则按行传递整行数据。关键点在于:它传的是Series或Series子集,不是单个标量值。
实际应用场景有哪些?比如计算每列均值、对某几列联合做归一化、按行拼接字段等。
- 传函数时可以携带额外参数,例如
df["age"].apply(lambda x, bias: x + bias, args=(-3,)) - 注意陷阱:
DataFrame.apply(len)返回的是每列的长度,而不是每个单元格的长度——很多人会误以为它是逐元素操作 - 性能方面,
apply比map或applymap要慢,因为它涉及对象构造和索引维护的开销
applymap:DataFrame的逐元素处理器
applymap的意图一目了然:对DataFrame中的每一个单元格施加操作,无视行列结构。它不关心索引、列名,只做纯元素级运算,类似于NumPy的向量化操作,但更灵活。
典型用途包括:统一格式化所有数字列(比如加单位)、对所有字符串调用strip()、批量类型转换。
- 只支持DataFrame,对Series调用会报
AttributeError - 无法区分列类型,如果DataFrame里混了数值和字符串,
applymap(str.upper)对数字列会报错 - 内部实现是Python循环,大数据量时明显慢于向量化操作。比如
df.astype(str).applymap(str.upper)就不如df.select_dtypes("object").applymap(str.upper)高效
如何选择?看操作对象和需求粒度
别去死记口诀,直接根据对象类型和需求来判断:
- 单列映射替换 → 首选
map,速度快、语义清晰 - 单列复杂计算,需要额外参数或条件分支 → 用
applyon Series - 整行或整列统计,或跨列逻辑处理 → 用
applyon DataFrame,记得指定axis - 所有单元格统一处理,且类型一致 → 用
applymap;否则考虑select_dtypes结合applymap的组合方式
最容易被忽略的一点:这三个函数都不会自动处理混合类型DataFrame中的异常类型。出错时通常只报第一个错误,需要自己提前做数据过滤,或者在函数内部用try/except包裹处理逻辑。