用对一把刀:Pandas 中的 map、apply、applymap 全景实战与进阶

用对一把刀:Pandas 中的 map、apply、applymap 全景实战与进阶

写 Python,像雕刻。Pandas 给了我们三把刀:map、apply、applymap。刀锋越锋利,越要知道何时用、怎么用、用到什么程度。


开篇引入

Python 从“一门优雅的脚本语言”成长为数据时代的通用底座。它连接 Web、自动化、数据科学与人工智能,被称为“胶水语言”,让工具与系统彼此“说话”。在数据处理领域,Pandas 是事实标准,而“如何把函数施加到数据上”这个看似简单的问题,往往决定了你的代码是否高效、稳定、可维护。

  • **为什么写这篇文章:**我在实际项目里见过太多“能跑但慢”“可用但难懂”的 DataFrame 操作。最常见的源头,就是没把 mapapplyapplymap 用对。本文从直觉到工程,带你建立清晰的心智模型,并给出一套可复制的实战模板。
  • **你将获得:**三者差异与适用场景的“速查表”;高频任务的代码模板;性能与可维护性的权衡方法;常见坑与避雷;以及可迁移到任意数据任务的思考框架。

三者差异一图看懂

维度 map apply applymap
作用对象 Series Series 或 DataFrame DataFrame
粒度 元素级(单列) Series:元素级;DataFrame:按行/按列 元素级(整表)
典型用途 值映射、字典编码 行/列聚合、行级多列逻辑 整表逐元素清洗/格式化
返回形态 Series 依函数返回:标量/Series/DataFrame DataFrame
性能倾向 快(字典/Series 映射更快) 视函数与 axis 而定(行级常慢) 最慢(逐元素 Python 调用)

经验顺序(快→慢):向量化/NumPy ufunc > 字典/Series 的 map > Series.apply(向量化函数)> DataFrame.apply(axis=1)> applymap。


基础概念与 API 要点

Series.map:单列值映射的首选

  • **适用场景:**编码字典映射、类别映射、值替换、函数逐元素映射。
  • 核心要点:
    • **支持三种输入:**函数、字典、Series。
    • **未命中行为:**字典/Series 映射未命中会得到 NaN;replace 的未命中默认保留原值。
    • 缺失项优化:na_action="ignore" 在函数模式下跳过 NaN,少做一次 Python 调用。
import pandas as pd

s = pd.Series(["M", "F", "X", None])
mapping = {
   
   "M": 1, "F": 0}

# 字典映射(未命中→NaN)
encoded = s.map(mapping)

# 函数映射(跳过 NaN)
encoded2 = s.map(lambda x: 1 if x == "M" else 0 if x == "F" else -1, na_action="ignore")
  • 与 replace 的区别:
    • **map:**未命中→NaN,强调“映射表定义全集”。
    • **replace:**未命中→保留原值,强调“只替换指定值”。

Series.apply:对单列做逐元素或归约变换

  • **适用场景:**需要函数逻辑,但已有向量化替代前暂用;复杂字符串/日期规则可先查 .str/.dt
  • **返回控制:**函数返回标量→Series;返回序列→可能“展开”为 DataFrame(也可先返回字典再构造)。
s = pd.Series(["  ab ", "cd  ", None])

# 字符串清洗:优先向量化 API
s1 = s.str.strip().str.lower()

# 万不得已再用 apply
s2 = s.apply(lambda x: x.strip().lower() if isinstance(x, str) else x)

DataFrame.apply:按行/按列执行函数

  • **适用场景:**行级规则(需要多列共同决策)、列级聚合/派生。
  • 关键参数:
    • **axis=0/“index”:**对每列的 Series 调用(常用于列级聚合或归一化)。
    • **axis=1/“columns”:**对每行的 Series 调用(多列逻辑,性能偏慢)。
    • result_type:“expand”(展开成多列)、“reduce”(尽量标量)、“broadcast”(按行/列广播)。
import pandas as pd

df = pd.DataFrame({
   
   
    "qty": [2, 3, 1],
    "price": [10.0, 20.0, 30.0],
    "city": ["Tokyo", "Osaka", "Nagoya"],
})

# 行级决策:需要多列
def score_row(row):
    base 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清水白石008

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值