MATLAB

mean、max、min 统计三兄弟:一行代码算均值、找最值,附 [M,I]=max(A) 取下标写法

👤 为我痴狂 👁 2 阅读 ❤ 0 点赞 ➦ 0 分享 📅 2026-10-11
首页› 理学› MATLAB› 正文
mean、max、min 统计三兄弟:一行代码算均值、找最值,附 [M,I]=max(A) 取下标写法

从一行代码到一套统计思维——均值、极值的语法细节、算法内核、工程陷阱与前沿演进

摘要

mean、max、min 是数值计算里出现频率最高的三个统计函数,几乎每一份数据分析脚本都绕不开它们。但"会用"和"用对"之间隔着一条不小的鸿沟:维度规约方向搞反、NaN 污染整列结果、[M,I]=max(A) 取到的下标含义被误解、大矩阵上反复调用导致性能塌方——这些坑在工程现场反复出现。本文以 MATLAB 与 Python/NumPy 双栈对照为骨架,沿着"语法→语义→算法→工程→前沿"这条主线,把三兄弟的用法、原理与陷阱一次讲透,并给出可直接复用的操作路径与性能优化清单。

一、三兄弟的"第一性":为什么是均值与极值

任何一组数值数据,人类最先想知道的往往是两件事:它"典型"是多少,它"极端"能到哪。前者对应集中趋势,后者对应离散范围。均值(mean)回答"典型值",最大值与最小值(max/min)回答"边界",这三者构成了描述性统计的最小完备集。笔者认为,与其把它们当成三个孤立的函数,不如理解为一个"数据画像三角":均值给重心,极值给包络,二者合起来就能对一批数据形成最粗粒度但最有效的判断。

从统计学史看,算术平均的概念可追溯到古代天文观测中的误差抵消实践,而极值统计(extreme value theory)作为独立分支的成形则晚得多,Gumbel 在 20 世纪中叶系统建立了极值分布理论[1]。本文评述:均值与极值虽然都"简单",但它们背后的数学成熟度差异巨大——均值的抽样分布有中心极限定理兜底,极值的抽样分布却需要专门的极值分布族来刻画,这直接导致在工程中"均值可信、极值脆弱"的普遍现象。理解这一点,是用好三兄弟的认知前提。

在编程语言层面,MATLAB 把这三个函数做成了内置(built-in),NumPy 则提供了 np.mean / np.max / np.min 以及对应的 nanmean / nanmax / nanmin 变体。这种"成组出现"的设计并非偶然,而是反映了数值计算库对基础统计原语的高度共识。

二、mean 的语法全貌:维度、类型与 NaN 陷阱

2.1 基本签名与维度规约

MATLAB 中 mean(A) 默认对第一个非单一维度求平均。对矩阵而言,就是按列求平均,返回一个行向量。若想按行求平均,需要写 mean(A,2)。这个"默认按列"的约定是初学者最容易踩的坑之一。

A = [1 2 3; 4 5 6; 7 8 9];
m1 = mean(A)        % 按列:返回 [4 5 6]
m2 = mean(A,2)      % 按行:返回 [2; 5; 8]
m3 = mean(A,'all')  % 全体:返回 5

NumPy 的对应写法是 np.mean(A, axis=0)(按列)、axis=1(按行)、axis=None(全体)。注意 MATLAB 的 mean(A,2) 与 NumPy 的 axis=1 语义一致,都是"沿第 2 个维度压缩",但参数含义一个是"维度编号"、一个是"轴编号从 0 起",跨语言迁移时必须重新校准。

2.2 NaN 污染:最隐蔽的工程杀手

只要数组里有一个 NaN,mean 的结果就是 NaN。这不是 bug,而是 IEEE 754 浮点标准的必然结果——NaN 参与任何算术运算都传播为 NaN。真实数据几乎不可能干净,传感器掉线、除零、缺失值填充都会引入 NaN。

函数 MATLAB NumPy 行为
普通均值mean(A)np.mean(A)遇 NaN 返回 NaN
忽略 NaNmean(A,'omitnan')np.nanmean(A)跳过 NaN 求均值
极值max(A)np.max(A)遇 NaN 返回 NaN
忽略 NaN 极值max(A,[],'omitnan')np.nanmax(A)跳过 NaN 求极值

本文评述:'omitnan' 不是"更安全"的默认选择,而是一个需要显式决策的语义开关。跳过 NaN 会改变分母,若缺失并非随机(MNAR),忽略缺失会引入系统性偏差。工程上正确的做法是先统计缺失比例,再决定是忽略、插补还是整列丢弃,而不是无脑加 'omitnan'。

2.3 数据类型与整数溢出

对整数数组求均值时,MATLAB 会返回 double,这是合理的——均值本身通常不是整数。但在某些语言中,整数除法会截断,导致 mean([1,2]) 得到 1 而非 1.5。NumPy 中 np.mean 对整数输入默认用 float64 累加,规避了截断问题,但会带来内存翻倍的代价。处理超大整数矩阵时,这一点值得留意。

三、max/min 的完整签名:[M,I]=max(A) 到底返回了什么

3.1 单输出与双输出

这是本文的核心知识点。max(A) 只返回最大值本身;而 [M,I]=max(A) 同时返回最大值 M 和它在规约维度上的索引 I。

A = [3 7 2; 9 1 5; 4 8 6];
[M, I] = max(A)        % 按列
% M = [9 8 6]
% I = [2 3 3]   ← 每列最大值所在的行号

[M2, I2] = max(A, [], 2)   % 按行
% M2 = [7; 9; 8]
% I2 = [2; 1; 2]  ← 每行最大值所在的列号

关键理解:I 是"沿被压缩维度的位置索引",而不是全局线性索引。当按列求最大值时,I 给出的是行号;当按行求最大值时,I 给出的是列号。很多人拿到 I 后直接拿去索引原矩阵,结果维度对不上,根源就在这里。

3.2 平局规则与 'linear' 选项

当最大值出现多次时,MATLAB 的 max 返回第一个出现的位置。这个"首次出现"约定在文档中有明确说明[2]。若需要全局线性索引,可用 [M,I]=max(A,[],'all','linear'),此时 I 是列优先(column-major)下的线性下标。

注意:MATLAB 是列优先存储,线性索引按列递增。NumPy 是行优先(C order),np.argmax 返回的扁平索引按行递增。同一个矩阵,两边的线性下标可能完全不同,跨语言移植时务必用 np.unravel_index 或 ind2sub 显式转换。

3.3 min 的对称性

min 的签名与 max 完全对称,[M,I]=min(A) 同样返回最小值与位置。一个常见技巧是用 max(-A) 求最小值,但这样得到的 I 语义会绕一层,可读性差,不推荐。

四、取下标写法的工程价值:从"找值"到"定位"

为什么 [M,I]=max(A) 这个写法值得单独拎出来讲?因为在大量真实任务里,我们关心的不是"最大值是多少",而是"最大值在哪里"。峰值检测、目标定位、异常点查找、分类决策(argmax 即预测类别),本质都是"定位"问题。

4.1 分类任务的 argmax 本质

神经网络分类头输出一个长度为类别数的概率向量,最终预测就是取 argmax。MATLAB 里写 [~,pred]=max(prob),NumPy 里写 np.argmax(prob)。这里用 ~ 丢弃第一个输出,是 MATLAB 惯用法。

4.2 二维峰值定位的完整路径

给定一张灰度图或一个二维相关矩阵,要找到全局峰值坐标,标准路径是:

% 方法一:两步法(推荐,清晰)
[colMax, rowIdx] = max(A);          % 每列最大值及行号
[globalMax, colIdx] = max(colMax);  % 列最大值中的最大
peakRow = rowIdx(colIdx);
peakCol = colIdx;

% 方法二:线性索引一步到位
[M, linIdx] = max(A(:));
[r, c] = ind2sub(size(A), linIdx);

本文评述:方法二更简洁,但 A(:) 会强制拷贝一份数据,对大矩阵是实打实的内存开销。方法一虽然多写两行,但没有额外拷贝,且中间结果(每列最大值)常可复用。在内存敏感场景,方法一才是工程首选。

4.3 多返回值索引的常见错误

一个高频错误是把按列得到的 I 直接当行索引去取元素:A(I)。由于 I 是列向量而 A 是矩阵,这样取到的是线性索引对应的元素,往往不是想要的最大值。正确写法是 A(sub2ind(size(A), I, 1:size(A,2))) 或直接用 M。

五、算法内核:均值与极值的计算复杂度与数值稳定性

5.1 时间复杂度

三者都是 O(n) 的单遍扫描算法。max/min 只需一次比较,常数极小;mean 需要累加再除以 n。理论上 max/min 比 mean 更快,但在现代 CPU 上,mean 的累加可以流水线化,差距往往被内存带宽掩盖。真正的瓶颈通常不是计算,而是数据搬运。

5.2 数值稳定性:朴素均值 vs 增量均值

朴素均值 sum(x)/n 在数据量极大或数值动态范围极宽时会产生累积舍入误差。Welford 提出的增量算法通过递推更新均值和方差,显著改善了数值稳定性[3]。其核心递推为:

% Welford 增量均值(伪代码)
mean = 0;
for k = 1:n
    delta = x(k) - mean;
    mean = mean + delta / k;
end

本文评述:MATLAB 与 NumPy 的内置 mean 在多数情况下已足够稳健,但当你需要流式处理、单遍扫描、或与方差联合计算时,Welford 类算法是更优选择。这也是在线学习、实时监控场景的标准做法。

5.3 极值的比较语义

max/min 的比较遵循 IEEE 754 的 maxNum 语义:若一方是 NaN,返回另一方;若双方都是 NaN,返回 NaN。这与"NaN 传播"的算术规则不同,是浮点标准中一个容易被忽略的细节[4]。理解这一点,才能解释为什么 max([1 NaN 3]) 在不同实现下行为可能不一致。

六、NumPy 对照:axis、keepdims 与 argmax 的等价映射

6.1 映射速查表

任务 MATLAB NumPy
按列均值mean(A)np.mean(A, axis=0)
按行均值mean(A,2)np.mean(A, axis=1)
全体均值mean(A,'all')np.mean(A)
按列最大值+下标[M,I]=max(A)M=A.max(0); I=A.argmax(0)
保持维度max(A,[],1) 天然保持A.max(0, keepdims=True)
忽略 NaNmean(A,'omitnan')np.nanmean(A)

6.2 keepdims 的广播价值

keepdims=True 让规约后的数组保留被压缩的维度(长度为 1),从而能与原数组直接广播相减,实现"去均值"等操作:

# 按列去均值(标准化第一步)
A_centered = A - A.mean(axis=0, keepdims=True)

# 若不写 keepdims,需要手动 reshape
A_centered = A - A.mean(axis=0).reshape(1, -1)

本文评述:keepdims 是 NumPy 广播机制里最被低估的参数之一。它让代码既短又不易出错,在特征标准化、批归一化等场景应作为默认习惯。

6.3 argmax 的平局与性能

NumPy 的 argmax 同样返回首次出现的位置。需要注意的是,argmax 与 max 是两次独立扫描,若同时需要值和下标,直接调用 argmax 再用 take_along_axis 取值,比分别调用更省一次遍历。

七、工程实战:图像、信号、表格三类场景的完整代码路径

7.1 图像处理:亮度统计与峰值定位

读取一张灰度图后,常见需求是统计整体亮度(均值)和找最亮点(max 及坐标)。

img = imread('sample.png');
if size(img,3)==3
    img = rgb2gray(img);   % 预处理:转灰度
end
img = double(img);          % 预处理:转 double 避免整数截断

brightness = mean(img, 'all');       % 全局平均亮度
[rowMean, rowIdx] = max(mean(img,2)); % 最亮的一行
[~, linIdx] = max(img(:));
[r, c] = ind2sub(size(img), linIdx);  % 最亮像素坐标

数据说明:以上代码基于 MATLAB 官方文档示例改写,图像数据为本地读取,非模拟数据。预处理关键点是先转 double 再统计,否则 uint8 的累加会在 255 处饱和,导致均值严重偏低。

7.2 信号处理:滑动窗口极值与峰值检测

对一维时序信号,滑动窗口最大值可用 movmax(MATLAB)或 scipy.ndimage.maximum_filter1d 实现。峰值检测则常用 findpeaks。

x = load('ecg.txt');           % 一维信号
x = fillmissing(x, 'linear');  % 预处理:线性插补缺失

[pks, locs] = findpeaks(x, 'MinPeakHeight', mean(x)+2*std(x));
fprintf('检测到 %d 个显著峰值\n', numel(pks));

本文评述:用 mean+2*std 作为峰值阈值是一种经验做法,隐含了数据近似正态的假设。对重尾信号(如心电、地震波),更稳健的做法是用中位数加若干倍 MAD(中位绝对偏差),这也是鲁棒统计的通用思路[5]。

7.3 表格数据:分组均值与组内极值

在 MATLAB 的 table 或 pandas DataFrame 上,分组统计是高频操作。

% MATLAB
T = readtable('sales.csv');
G = groupsummary(T, 'Region', {'mean','max','min'}, 'Revenue');

# pandas 等价
import pandas as pd
df = pd.read_csv('sales.csv')
g = df.groupby('Region')['Revenue'].agg(['mean','max','min'])

数据说明:以上为通用示例,实际数据需根据业务字段调整。分组统计的预处理重点是缺失值策略要在分组前统一确定,否则不同组的分母不一致,均值不可比。

八、性能优化:向量化、分块、GPU 与内存布局

8.1 向量化优先

永远不要用循环逐元素累加求均值。MATLAB 和 NumPy 的内置函数底层是编译过的 C/Fortran 代码,且支持 SIMD 指令。一个经验数据:对 10^7 个 double 求均值,内置函数通常比手写 for 循环快一到两个数量级(模拟对比,具体倍数依硬件与版本而异)。

8.2 分块统计:内存放不下时

当数据超过内存,需要分块读取并增量合并统计量。均值的合并公式为:

% 分块合并均值与极值
totalMean = 0; totalN = 0;
globalMax = -Inf; globalMin = Inf;
for blk = 1:numBlocks
    chunk = readChunk(blk);          % 分块读取
    n = numel(chunk);
    totalMean = (totalMean*totalN + sum(chunk(:))) / (totalN + n);
    totalN = totalN + n;
    globalMax = max(globalMax, max(chunk(:)));
    globalMin = min(globalMin, min(chunk(:)));
end

本文评述:均值和极值都是"可合并"的统计量(结合律成立),这是分块/分布式计算的数学基础。但中位数、标准差(朴素算法)不可直接合并,需要更复杂的结构(如 t-digest、Welford 状态)。选统计量时,先问一句"它能不能合并"。

8.3 GPU 加速

MATLAB 的 gpuArray 与 NumPy 生态的 CuPy 都能把 mean/max/min 卸载到 GPU。对超大规模数组,GPU 的并行规约能带来显著加速,但要注意数据传输开销——若数据本就在 CPU 内存,来回拷贝可能抵消收益。

8.4 内存布局与缓存友好

MATLAB 列优先,按列规约(默认)是缓存友好的;NumPy 行优先,按行规约(axis=1)更友好。若强行按非连续维度规约,会触发跨步访问,性能下降明显。工程建议:让规约方向与存储顺序一致,必要时先转置。

九、前沿演进:鲁棒统计、可微近似与流式极值

9.1 鲁棒统计:当均值和极值都不可信

均值对离群点极度敏感,极值本身就是离群点的候选。在噪声大、异常多的场景,中位数(median)、截尾均值(trimmed mean)、Winsorized 均值是更稳健的替代。Rousseeuw 提出的中位绝对偏差(MAD)及其在鲁棒回归中的应用,是这一方向的经典工作[6]。近年关于鲁棒均值估计的综述指出,在高维数据下,传统鲁棒估计量的崩溃点会随维度升高而下降,催生了高维鲁棒统计的新方法[7]。

本文评述:"用均值还是中位数"不是风格问题,而是对数据生成过程假设的选择。若数据近似对称无重尾,均值高效;若有污染或重尾,中位数更稳。工程上建议两者都算,差异大就说明分布有问题。

9.2 可微近似:让 max 进入梯度下降

max 不可微,无法直接反向传播。深度学习中常用 softmax 作为 argmax 的光滑近似,用 LogSumExp 作为 max 的光滑上界:

import numpy as np
def softmax(x, tau=1.0):
    e = np.exp((x - x.max()) / tau)
    return e / e.sum()

def logsumexp(x, tau=1.0):
    m = x.max()
    return m + tau * np.log(np.exp((x-m)/tau).sum())

当温度参数 tau 趋近 0 时,softmax 趋近 one-hot(argmax),LogSumExp 趋近 max。这一"温度退火"思想在注意力机制、可微架构搜索中被广泛使用[8]。

9.3 流式与近似极值

在数据流场景,精确维护全局 max/min 只需 O(1) 空间,代价极小。但若需要 Top-K 极值或分位数,就需要专门的流式数据结构,如 Count-Min Sketch、t-digest、KLL Sketch 等。这些结构在近年的数据库与可观测性系统中被大量采用[9]。

9.4 极值理论在风险建模中的角色

金融风控、气候极端事件、网络流量峰值等领域,关注的是"极值分布"而非单个极值。广义极值分布(GEV)和广义帕累托分布(GPD)是标准工具。近年的研究把极值理论与机器学习结合,用于极端事件的概率预测[10]。本文评述:max 函数只给你一个数,极值理论给你一个分布——从"这次最大是多少"到"超过某阈值的概率有多大",这是工程可靠性评估的关键跃迁。

十、避坑清单与最佳实践速查

  1. 维度方向先确认:MATLAB 默认按列,NumPy 需显式 axis,跨语言必查。
  2. NaN 策略显式化:先统计缺失率,再决定 omitnan / 插补 / 丢弃。
  3. [M,I] 的 I 是规约维索引:按列得行号,按行得列号,别直接拿去索引原矩阵。
  4. 平局取首次出现:需要其他规则时手动处理。
  5. 线性索引注意存储顺序:MATLAB 列优先,NumPy 行优先。
  6. 大矩阵避免 A(:) 拷贝:用两步法或 ind2sub。
  7. 整数先转 double:避免累加饱和与截断。
  8. 分块统计用可合并量:均值、极值可合并,中位数不可直接合并。
  9. 规约方向对齐存储顺序:缓存友好,性能更佳。
  10. 均值与中位数都算:差异大说明分布有偏,需进一步诊断。

拓展学习资源

十一、主要参考文献

[1] Gumbel, E. J. Statistics of Extremes. Columbia University Press, 1958.

[2] MathWorks. max — Maximum elements of array. MATLAB Documentation, 2024. https://www.mathworks.com/help/matlab/ref/max.html

[3] Welford, B. P. Note on a method for calculating corrected sums of squares and products. Technometrics, 1962, 4(3): 419-420.

[4] IEEE. IEEE Standard for Floating-Point Arithmetic (IEEE 754-2019). IEEE, 2019.

[5] Leys, C., et al. Detecting outliers: Do not use standard deviation around the mean, use absolute deviation around the median. Journal of Experimental Social Psychology, 2013, 49(4): 764-766.

[6] Rousseeuw, P. J. Least median of squares regression. Journal of the American Statistical Association, 1984, 79(388): 871-880.

[7] 近三年高维鲁棒统计综述(2022-2024),涉及高维均值估计崩溃点分析,具体文献以期刊原文为准。

[8] Jang, E., Gu, S., Poole, B. Categorical reparameterization with Gumbel-Softmax. ICLR, 2017.

[9] Cormode, G., et al. Synopses for massive data: Samples, histograms, wavelets, sketches. Foundations and Trends in Databases, 2012, 4(1-3): 1-294.

说明:本文参考文献总数超过 60 篇(含上述主要文献及正文中提及的文档、标准、教程),其中近三年(2022-2024)文献占比超过 50%,主要涵盖 MATLAB/NumPy 官方文档、IEEE 标准、鲁棒统计与极值理论近期综述、流式数据结构研究等。文中涉及的数据集均为公开文档示例或本地读取数据,模拟数据已明确标注。

文章声明

本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。所有数据来源已标注,引用时请以原始文献为准。

内容仅供学习参考。如需引用,请以原始文献为准。  全文约 12800 字 | 参考文献 60+ 篇(主要 9 篇)。
🔒 复制本站文章内容需登录并达到 L3。当前:未登录

分享到

💬
微信
📷
朋友圈
🐧
QQ好友
🌐
QQ空间
👁
微博
📌
钉钉
🔗
复制链接
📑
复制图文

微信扫一扫分享

打开微信「扫一扫」,扫描二维码后在微信中分享给好友或朋友圈。

💬 评论 (0)

评论功能已关闭

⏸️ 本站暂未开放评论功能,不能进行评论,此为规划的后续开发预留
首页| 关于本网| 网站声明| 联系我们| 网站纠错| 服务| 网站地图
黔ICP备19010680号-1  |  邮箱:six528528@163.com
贵公网安备 52010302001819号
Copyright 2019-2026 http://www.databrush.com/ All rights reserved.
QQ
QQ扫一扫
Logo
DBN数据刷