
本文介绍一种纯向量化、无显式循环的 NumPy 方法,通过 np.maximum.accumulate 与 np.diff 配合 np.where,精准保留每行中每个新高值的首次出现位置,其余元素置为 0。
本文介绍一种纯向量化、无显式循环的 numpy 方法,通过 np.maximum.accumulate 与 np.diff 配合 np.where,精准保留每行中每个新高值的首次出现位置,其余元素置为 0。
在处理时间序列、首达概率或单调性检测等任务时,常需从每行数组中提取“首个严格递增点”——即仅保留每个新达到的最大值的第一次出现,后续重复或回落值全部清零。传统循环实现低效且难以扩展,而 NumPy 提供了简洁高效的向量化解法。
核心思路分两步:
-
累积最大值追踪:对每行沿列方向(
axis=1)应用np.maximum.accumulate(arr),生成一个与原数组同形的矩阵,其中每个位置(i, j)存储该行前j+1个元素的最大值; -
识别首次跃升点:对该累积最大值矩阵沿列计算差分(使用
prepend=0确保首列可比),差分结果非零的位置即为“当前值首次打破历史最大值”的时刻,对应原数组中应保留的值;其余位置统一置 0。
以下是完整实现代码:
import numpy as np
arr = np.array([
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5],
[1, 1, 2, 2, 2, 3, 2, 2, 3, 3, 3, 4, 4],
[3, 2, 1, 2, 1, 1, 2, 3, 4, 5, 4, 3, 2]
])
# 步骤1:逐行累积最大值
m_arr = np.maximum.accumulate(arr, axis=1)
# 步骤2:计算差分(首列补0),标记跃升位置
# diff(..., prepend=0) 返回长度与原数组相同的差分数组,首项为 m_arr[:,0] - 0
mask = np.diff(m_arr, axis=1, prepend=0) != 0
# 步骤3:按掩码选择原值或0
result = np.where(mask, arr, 0)
print(result)
输出结果与预期完全一致:
[[1 0 0 2 0 0 3 0 0 4 0 5 0] [1 0 2 0 0 3 0 0 0 0 0 4 0] [3 0 0 0 0 0 0 0 4 5 0 0 0]]
⚠️ 注意事项:
- 该方法严格识别“严格递增”(即
> current_max),等于当前最大值的重复项会被过滤; -
prepend=0是关键,确保首列差分值为m_arr[:, 0] - 0,从而正确保留每行第一个元素(只要它大于 0);若数据含负数且首值为负,逻辑仍成立,因prepend=0仅用于触发首次比较,不影响后续逻辑; - 时间复杂度为 O(n×m),空间复杂度 O(n×m),远优于 Python 循环,适合大规模数组处理。
总结:利用 maximum.accumulate 构建历史最大值轨迹,再以 diff + where 定位跃升点,是 NumPy 中处理“首次突破”类问题的经典范式——简洁、高效、可读性强,值得纳入高性能数值计算工具箱。











