apply在axis=1下特别慢,因其本质是Python层逐行循环,每行转Series并调用函数,引发对象创建、属性查找、类型检查等解释器开销,且无法利用NumPy底层C实现和CPU向量化指令。
apply 在 axis=1 下特别慢?因为 apply 在 axis=1 时,本质是 Python 层面的逐行循环:每行被包装成一个 Series 对象,再调用你的函数一次。这触发了大量 Python 解释器开销——对象创建、属性查找、类型检查、函数调用栈压入/弹出。而向量化操作(如 df['A'] + df['B'])直接调用底层 NumPy 的 C 实现,跳过所有 Python 循环,对整列做一次内存连续运算。
axis=1 的 apply 还有哪些隐藏成本?除了循环本身,这些细节也在拖慢速度:
raw=False(默认):每行传入的是带索引的 Series,不是纯数组,额外有 label 查找和对齐开销result_type=None:返回结果类型需动态推断,尤其当函数返回 list 或 dict 时,会触发额外结构解析np.log,也受限于单次调用上下文Series 对象,频繁触发垃圾回收axis=1 的 apply?别只看代码写了 axis=1,还要确认实际执行路径:
%%time 或 timeit 测真实耗时,而非“看起来像向量化”row['col_name'] 或 row.index —— 这说明你依赖了 Series 接口,无法被 raw=True 加速loc 赋值,例如:df.loc[df['e'] == 10, 'new'] = df['c'] * df['d']
axis=1 的 apply?只有当逻辑真正无法用向量化表达式描述时才保留它,比如:
shift + 累积函数,或改用 numba.jit
.str 方法链无法覆盖即便如此,也建议先尝试 swifter.apply 并行化,或把逻辑抽到 numba.vectorize 中——但要注意:一旦你开始为 apply 找加速方案,就说明问题本身可能更适合换种建模方式。