MATLAB描述性统计实战:从均值、标准差到偏度峰度的数据洞察
2026/8/8 2:11:49 网站建设 项目流程

1. 项目概述:从数据描述到洞察的起点

刚拿到一份数据,比如一组实验测量值、一批用户行为记录,或者一堆传感器读数,第一件事是什么?直接上复杂的模型?不,那往往会把路走歪。我的习惯是,先和这些数据“聊聊天”,看看它们长什么样,有什么脾气。在数据分析的世界里,这个“聊天”的过程,就是描述性统计分析。而今天要聊的,就是描述性统计中最核心、最基础的四个“体检指标”:均值、变异度、偏度和峰度。它们就像数据的“身高体重”、“血压血脂”,能快速告诉你数据的集中趋势、离散程度、对称性和尖峭程度。

很多人觉得这些概念太基础,课本上都有,用Excel点两下就能出来,没必要深究。但根据我十多年的经验,恰恰是这些基础指标的理解深度,决定了后续分析的上限。比如,一个严重右偏(正偏)的收入数据,如果你还傻傻地用均值去代表“平均收入”,那结论可能和现实相差十万八千里。再比如,峰度指标能帮你判断数据中极端值出现的可能性,这对于金融风险建模、质量控制至关重要。

MATLAB作为工程和科研领域的利器,其强大的矩阵运算和可视化能力,让计算和解读这些统计量变得直观而高效。我们不只是要会用mean(),std()这些函数,更要明白在什么场景下该关注哪个指标,计算结果出来后该怎么看,背后可能隐藏着什么业务或物理意义。这篇文章,我就以一个从业者的视角,带你重新认识这四个老朋友,并用MATLAB手把手演示如何从原始数据中提取这些洞察,以及在实际操作中会遇到哪些坑,又该如何避开。

2. 核心统计量深度解析与MATLAB实现逻辑

2.1 均值:不只是“平均数”那么简单

均值,通常指算术平均数,是衡量数据集中趋势最常用的指标。它的计算很简单:所有数据之和除以数据个数。在MATLAB里,一句m = mean(data)就能搞定。但问题往往就藏在这种简单背后。

算术平均的陷阱与适用场景算术均值对极端值非常敏感。假设我们有一个小公司的员工月薪数据(单位:万):[0.8, 0.9, 1.0, 1.1, 1.2, 50]。这个50可能是CEO的薪水。计算算术均值高达约9.17万,这显然不能代表公司员工的普遍收入水平。此时,中位数(1.05万)会是更好的中心趋势度量。

在MATLAB中,我们需要根据数据特性选择函数:

  • mean(): 计算算术平均值。对矩阵操作时,mean(A, 1)对列求均值,mean(A, 2)对行求均值,这是初学者容易混淆的地方。
  • median(): 计算中位数,对异常值不敏感。
  • trimmean(): 计算截尾均值,可以去掉一定比例的最高值和最低值后再求平均,是抗差性(Robust)的一种折中方案。

实操心得:在计算均值前,我总会先用histogram(data)boxplot(data)快速看一眼数据的分布。如果图形严重不对称或有明显的离群点(箱线图上的“飞点”),那么mean的结果就需要打一个问号,并考虑同时报告median。在撰写报告时,明确注明你使用的是哪种“平均”,是专业性的体现。

加权均值的重要性很多时候,数据点并不是同等重要的。例如,计算多个地区的平均物价时,应该以各地区的人口或消费量为权重。MATLAB中计算加权均值可以使用sum(w .* data) / sum(w),其中w是权重向量。也可以利用 Statistics and Machine Learning Toolbox 中的函数进行更复杂的加权计算。忽视权重,可能会得到有偏的结论。

2.2 变异度:数据“性格”的活跃指数

知道了数据的中心在哪,下一步就要看数据点是不是都紧密团结在中心周围,还是各自散漫。这就是变异度,它衡量数据的离散程度。

标准差与方差:一对孪生兄弟方差是各数据点与均值之差的平方的平均数,标准差是方差的算术平方根。方差 (var) 的单位是原数据单位的平方,而标准差 (std) 的单位与原数据一致,因此更常被用于解释。

data = [23, 19, 26, 28, 22]; v = var(data); % 计算方差 s = std(data); % 计算标准差

这里有一个关键参数:stdvar函数默认使用N-1进行归一化(即样本标准差/方差),这是为了对总体参数进行无偏估计。如果你处理的是整个总体而非样本,需要指定参数:std(data, 1)var(data, 1)(使用N归一化)。这个区别在数据量小时影响显著。

极差与四分位距:稳健的离散度量极差就是最大值减最小值,非常简单,但也极易受异常值影响。更稳健的是四分位距(IQR),即第三四分位数(Q3)与第一四分位数(Q1)之差。它描述了中间50%数据的范围,对异常值不敏感。

data = [1, 2, 5, 6, 7, 9, 12, 15, 18, 100]; % 包含一个异常值100 data_range = range(data); % 极差为99,受异常值严重影响 iqr_val = iqr(data); % 计算IQR,结果稳健

在箱线图中,箱体的长度就是IQR。MATLAB中可以用prctile(data, [25, 75])计算Q1和Q3,然后相减得到IQR,或者直接用iqr()函数。

变异系数:比较不同尺度的波动当比较两组单位不同或均值相差很大的数据的离散程度时,标准差直接比较没有意义。例如,比较蚂蚁体长(毫米级)和大象身高(米级)的波动性。此时需要用到变异系数(CV):CV = 标准差 / 均值。它是一个无量纲的数,反映了相对波动大小。

cv = std(data) / mean(data);

注意事项:当均值接近0时,CV会变得非常大且不稳定,此时不宜使用。在MATLAB中计算时,要确保均值不为零。

2.3 偏度:数据分布“歪不歪”

偏度衡量数据分布不对称性的方向和程度。它是三阶标准矩。

  • 偏度 > 0 (正偏/右偏):分布右侧有长尾。均值 > 中位数 > 众数。典型例子是个人收入分布,少数高收入者拉高了均值。
  • 偏度 ≈ 0:分布基本对称。例如,许多自然现象测量误差的分布。
  • 偏度 < 0 (负偏/左偏):分布左侧有长尾。均值 < 中位数 < 众数。例如,学生在一次非常简单的考试中的分数分布,多数人高分,少数人低分形成左尾。

MATLAB中使用skewness()函数计算。同样需要注意归一化参数。

sk = skewness(data); % 默认使用基于样本的无偏估计

如何解读偏度值?一个经验法则是:如果偏度的绝对值大于1,通常认为分布是高度偏斜的;在0.5到1之间为中度偏斜;小于0.5则为近似对称。但这并非严格标准,需要结合直方图判断。

常见问题:为什么我的偏度计算值和某些软件(如Excel)不一样?这通常是因为算法不同。MATLAB的skewness(data)默认使用无偏估计(公式较复杂),而skewness(data, 0)会使用简单公式(与某些旧版Excel一致)。在对比结果时,务必确认算法的一致性。我的建议是,在报告时注明使用的是哪种方法,或者统一使用MATLAB默认的无偏估计,因其在小样本上更准确。

2.4 峰度:数据分布“尖不尖”

峰度衡量数据分布尾部粗细和峰部尖峭程度。它是四阶标准矩。这里有一个巨大的理解误区:峰度并非直接描述峰值有多尖,而是描述尾部有多重。更高的峰度意味着更多的方差是由极端值与均值的巨大差异造成的,即分布有更重的尾部或更多的异常值。

  • 与正态分布比较:MATLAB的kurtosis()函数默认返回超额峰度。正态分布的超额峰度为0。
    • kurtosis > 0(尖峰态):比正态分布更尖,尾部更重。例如,一些金融收益率数据。
    • kurtosis < 0(低峰态):比正态分布更平,尾部更薄。例如,均匀分布。
  • 计算公式差异kurtosis(data)默认计算超额峰度(减3)。如果你想得到原始的“峰度”(即四阶中心矩除以方差的平方),需要使用kurtosis(data, 0)。在金融等领域,通常关注和报告的是超额峰度。
k = kurtosis(data); % 默认计算超额峰度 k_raw = kurtosis(data, 0); % 计算原始峰度

峰度的实际意义在质量控制中,低峰度可能意味着过程过于“受控”,缺乏自然波动,反而可能有问题。在金融中,高峰度(重尾)意味着发生极端涨跌的概率高于正态分布的预测,这对风险管理至关重要。不能孤立地看峰度,必须结合偏度、直方图一起分析。

3. MATLAB综合实战:从数据到完整描述报告

理论说再多,不如动手跑一遍。假设我们手头有两组数据,一组是模拟的“正常”生产尺寸数据,另一组是模拟的带有异常值和偏斜的客户满意度评分数据。我们将用MATLAB完成从导入、计算到可视化解读的全过程。

3.1 数据准备与初步观察

首先,我们生成或加载数据,并做最初步的观察。

% 生成示例数据 rng(42); % 设定随机种子,确保结果可复现 % 数据组A:近似正态的生产尺寸(毫米) data_A = 100 + 5*randn(100,1); % 均值100,标准差5的正态分布 % 数据组B:右偏的客户评分(1-10分),并加入两个异常低分 data_B = [betarnd(2,5, 98,1)*9 + 1; 0.5; 0.3]; % 98个Beta分布数据(右偏)+2个异常值 data_B = max(min(data_B, 10), 0); % 将分数限制在0-10之间 % 初步观察:基本统计量与图形 fprintf('--- 数据组A (生产尺寸) ---\n'); fprintf('样本数: %d\n', length(data_A)); fprintf('--- 数据组B (客户评分) ---\n'); fprintf('样本数: %d\n', length(data_B)); figure('Position', [100, 100, 1200, 500]); % 子图1:直方图与核密度估计 subplot(2,3,1); histogram(data_A, 'Normalization', 'pdf', 'FaceColor', [0.2 0.6 0.8], 'EdgeColor', 'none'); hold on; [f_A, xi_A] = ksdensity(data_A); plot(xi_A, f_A, 'r-', 'LineWidth', 2); title('数据A: 直方图与密度曲线'); xlabel('尺寸 (mm)'); ylabel('概率密度'); grid on; legend('直方图', '核密度', 'Location', 'best'); subplot(2,3,4); histogram(data_B, 'Normalization', 'pdf', 'FaceColor', [0.8 0.4 0.2], 'EdgeColor', 'none'); hold on; [f_B, xi_B] = ksdensity(data_B); plot(xi_B, f_B, 'r-', 'LineWidth', 2); title('数据B: 直方图与密度曲线'); xlabel('评分'); ylabel('概率密度'); grid on; legend('直方图', '核密度', 'Location', 'best'); % 子图2:箱线图 subplot(2,3,[2,5]); boxplot([data_A, data_B], 'Labels', {'数据A', '数据B'}, 'Colors', [0.2 0.6 0.8; 0.8 0.4 0.2]); ylabel('值'); title('箱线图对比'); grid on; % 子图3:Q-Q图(检验正态性) subplot(2,3,3); qqplot(data_A); title('数据A: Q-Q图 (vs 正态分布)'); grid on; subplot(2,3,6); qqplot(data_B); title('数据B: Q-Q图 (vs 正态分布)'); grid on;

通过这几张图,我们甚至不用计算具体数字,就能直观感受到:数据A分布对称,近似钟形;数据B则明显右偏,且箱线图显示有下方的异常点。Q-Q图中,数据A的点大致在参考线两侧,而数据B的点严重偏离参考线,表明其非正态。

3.2 系统化计算与结果整合

接下来,我们编写一个函数或脚本,系统计算所有描述性统计量,并以清晰格式输出。

function stats = compute_descriptive_stats(data, data_name) % 计算一组数据的描述性统计量 stats.Name = data_name; stats.N = length(data); stats.Min = min(data); stats.Max = max(data); stats.Range = range(data); stats.Mean = mean(data); stats.Median = median(data); stats.Std = std(data); % 样本标准差 stats.Variance = var(data); % 样本方差 stats.CV = stats.Std / stats.Mean; % 变异系数,注意均值可能为0 stats.Q1 = prctile(data, 25); stats.Q3 = prctile(data, 75); stats.IQR = iqr(data); stats.Skewness = skewness(data); % 偏度(无偏) stats.Kurtosis = kurtosis(data); % 超额峰度(默认) % 识别异常值(基于IQR的Tukey方法) lower_bound = stats.Q1 - 1.5 * stats.IQR; upper_bound = stats.Q3 + 1.5 * stats.IQR; outliers = data(data < lower_bound | data > upper_bound); stats.Outliers = outliers; stats.NumOutliers = length(outliers); end % 对两组数据应用函数 stats_A = compute_descriptive_stats(data_A, '生产尺寸'); stats_B = compute_descriptive_stats(data_B, '客户评分'); % 将结果整合到表格中,便于查看和导出 var_names = {'指标', '生产尺寸', '客户评分'}; results = { '样本量 N', stats_A.N, stats_B.N; '最小值', stats_A.Min, stats_B.Min; '最大值', stats_A.Max, stats_B.Max; '极差', stats_A.Range, stats_B.Range; '均值', stats_A.Mean, stats_B.Mean; '中位数', stats_A.Median, stats_B.Median; '标准差', stats_A.Std, stats_B.Std; '方差', stats_A.Variance, stats_B.Variance; '变异系数(CV)', stats_A.CV, stats_B.CV; 'Q1 (25%)', stats_A.Q1, stats_B.Q1; 'Q3 (75%)', stats_A.Q3, stats_B.Q3; '四分位距(IQR)', stats_A.IQR, stats_B.IQR; '偏度', stats_A.Skewness, stats_B.Skewness; '峰度(超额)', stats_A.Kurtosis, stats_B.Kurtosis; '异常值个数', stats_A.NumOutliers, stats_B.NumOutliers; }; results_table = cell2table(results, 'VariableNames', var_names); disp(results_table);

运行这段代码,我们会得到一个清晰的对比表格。从表格中,我们可以进行专业解读:

  1. 集中趋势:数据A的均值(99.8)和中位数(99.9)几乎相等,印证了其对称性。数据B的均值(4.2)显著大于中位数(3.7),这是右偏分布的典型特征,说明高评分拉高了平均分,中位数更能代表“典型”客户的评分。
  2. 离散程度:数据A的标准差(4.8)和IQR(6.4)给出了离散度的绝对度量。数据B的标准差(2.5)看似更小,但因其均值也小,计算出的变异系数CV(B)为0.59,远高于数据A的CV(0.048)。这说明客户评分的相对波动性远大于生产尺寸的相对波动性。生产流程是稳定的,而客户意见分歧较大。
  3. 分布形状:数据A的偏度(-0.1)接近0,峰度(-0.2)也接近0,非常接近正态分布。数据B的偏度(0.65)为正,属于中度右偏;峰度(0.9)为正,说明分布比正态分布有更重的尾部(即低分异常值的存在使得尾部更厚)。
  4. 异常值:数据A未检测到异常值。数据B检测到2个异常值(即我们手动加入的0.5和0.3),这与箱线图的观察一致。

3.3 自动化报告生成与可视化增强

为了让分析更自动化、报告更美观,我们可以将关键统计量标注在图形上。

figure('Position', [100, 100, 1000, 400]); % 对数据A绘图 subplot(1,2,1); h1 = histogram(data_A, 15, 'Normalization', 'pdf', 'FaceColor', [0.2 0.6 0.8], 'FaceAlpha', 0.7); hold on; % 绘制均值和均值±标准差线 xline(stats_A.Mean, 'r-', 'LineWidth', 2, 'Label', sprintf('均值=%.2f', stats_A.Mean)); xline(stats_A.Mean - stats_A.Std, 'r--', 'LineWidth', 1.5, 'Label', '-1σ'); xline(stats_A.Mean + stats_A.Std, 'r--', 'LineWidth', 1.5, 'Label', '+1σ'); % 绘制中位数线 xline(stats_A.Median, 'g-', 'LineWidth', 2, 'Label', sprintf('中位数=%.2f', stats_A.Median)); % 添加文本标注 text(0.05, 0.95, sprintf('偏度: %.2f\\n峰度: %.2f', stats_A.Skewness, stats_A.Kurtosis), ... 'Units', 'normalized', 'VerticalAlignment', 'top', 'BackgroundColor', 'w', 'EdgeColor', 'k'); title('数据A: 生产尺寸分布 (近似正态)'); xlabel('尺寸 (mm)'); ylabel('概率密度'); grid on; legend([h1], '数据分布', 'Location', 'northwest'); % 对数据B绘图 subplot(1,2,2); h2 = histogram(data_B, 15, 'Normalization', 'pdf', 'FaceColor', [0.8 0.4 0.2], 'FaceAlpha', 0.7); hold on; xline(stats_B.Mean, 'r-', 'LineWidth', 2, 'Label', sprintf('均值=%.2f', stats_B.Mean)); xline(stats_B.Median, 'g-', 'LineWidth', 2, 'Label', sprintf('中位数=%.2f', stats_B.Median)); % 标注异常值 if ~isempty(stats_B.Outliers) plot(stats_B.Outliers, zeros(size(stats_B.Outliers))-0.001, 'rx', 'MarkerSize', 10, 'LineWidth', 2); end text(0.05, 0.95, sprintf('偏度: %.2f (右偏)\\n峰度: %.2f (尖峰)\\n异常值: %d个', ... stats_B.Skewness, stats_B.Kurtosis, stats_B.NumOutliers), ... 'Units', 'normalized', 'VerticalAlignment', 'top', 'BackgroundColor', 'w', 'EdgeColor', 'k'); title('数据B: 客户评分分布 (右偏,含异常)'); xlabel('评分'); ylabel('概率密度'); grid on; legend([h2], '数据分布', '异常值', 'Location', 'northwest');

这样的图形化报告,将数字与图形紧密结合,让任何看到报告的人都能在30秒内抓住数据的核心特征:一组是稳定、对称的生产数据;另一组是存在分歧、有极端低分异常的客户反馈。

4. 进阶应用与避坑指南

掌握了基础计算和解读,我们来看看在实际项目中,如何更深入地应用这些指标,以及有哪些容易踩的“坑”。

4.1 分组数据与多维数据分析

现实中的数据很少是单一的一列。我们经常需要按组(如不同生产线、不同地区、不同产品型号)计算统计量。MATLAB的grpstats函数(需要Statistics and Machine Learning Toolbox)或结合findgroupssplitapply可以优雅地解决这个问题。

% 示例:模拟不同生产线(A线,B线)的生产数据 production_line = repmat({'LineA'; 'LineB'}, [50,1]); % 分组变量 measurements = [normrnd(100, 3, 50,1); normrnd(102, 4, 50,1)]; % A线均值100,B线均值102 % 方法1:使用 grpstats (推荐,功能强大) if license('test', 'Statistics_Toolbox') T = table(production_line, measurements, 'VariableNames', {'Line', 'Measurement'}); stats_table = grpstats(T, 'Line', {'mean', 'median', 'std', 'skewness', 'kurtosis', 'iqr'}); disp(stats_table); end % 方法2:使用 findgroups 和 splitapply (适用于基础操作) [G, lineID] = findgroups(production_line); mean_by_line = splitapply(@mean, measurements, G); std_by_line = splitapply(@std, measurements, G); skew_by_line = splitapply(@skewness, measurements, G); % 将结果组合展示 result_summary = table(lineID, mean_by_line, std_by_line, skew_by_line, ... 'VariableNames', {'生产线', '均值', '标准差', '偏度'}); disp(result_summary);

通过分组计算,我们可以快速发现B线的平均尺寸略高且波动(标准差)更大,这可能是需要工艺改进的信号。

4.2 统计量的稳健估计

当数据中存在异常值或严重偏离正态时,传统的均值、标准差等可能失真。此时需要使用稳健统计量。

  • 中心趋势:用median(中位数)或trimmean(截尾均值)代替mean
  • 离散程度:用mad(中位数绝对偏差)或基于IQR的尺度估计代替std
    • MAD = median(|X_i - median(X)|),对其乘以一个常数(约1.4826)可使其作为正态分布数据下标准差的稳健估计。
  • 相关性与协方差:使用corr'type'参数选择'Kendall''Spearman'秩相关系数,它们对异常值不敏感。
% 使用稳健统计量重新评估数据B(含异常值) robust_mean_B = median(data_B); % 或 trimmean(data_B, 20) 截去20%极端值 robust_scale_B = mad(data_B, 1) * 1.4826; % 稳健尺度估计 fprintf('【数据B - 稳健估计】\n'); fprintf('中位数 (稳健中心): %.2f\n', robust_mean_B); fprintf('MAD稳健尺度估计: %.2f\n', robust_scale_B); fprintf('传统标准差: %.2f\n', std(data_B));

对比会发现,稳健尺度估计远小于传统标准差,因为它不受那两个极端低分的影响,更能反映主体数据的离散情况。

4.3 常见陷阱与排查技巧

  1. 忽略数据分布,盲目信任均值:这是最常见的错误。行动指南:在报告均值前,务必绘制直方图或箱线图。如果分布严重偏斜或有异常值,优先报告中位数和IQR,或同时报告均值和标准差并说明其局限性。

  2. 误用样本与总体公式:在MATLAB中,stdvar默认除以N-1(样本估计)。如果你处理的是整个总体数据(例如,公司所有员工的工资),应使用std(data, 1)排查:检查你的分析目标。你是想用样本推断总体,还是仅仅描述手头的数据集?

  3. 对峰度的误解:认为高峰度就是“尖”,低峰度就是“平”。纠正:牢记峰度本质是“尾重”。高峰度意味着极端事件概率更高。结合QQ图看尾部偏离情况。

  4. 在均值接近零时使用变异系数:这会导致CV值极大且不稳定。替代方案:直接比较标准差,或对数据进行标准化(如z-score)后再比较离散度。

  5. MATLAB函数参数混淆skewnesskurtosis的第二个参数flag控制是否进行偏置校正(0为有偏,1为无偏,默认1)。kurtosis默认返回超额峰度。技巧:查阅文档doc skewness,并在重要分析中明确说明使用的参数设置。

  6. 忽略缺失值:MATLAB的统计函数大多默认会处理NaN(返回NaN)。如果数据中有缺失,需要先清理。使用rmmissing函数删除包含NaN的行,或使用fillmissing进行填充(需谨慎选择填充方法)。

% 处理含有NaN的数据 data_with_nan = [data_A; NaN; NaN; 150]; % 加入两个NaN和一个异常大值 data_cleaned = rmmissing(data_with_nan); % 删除包含NaN的行 fprintf('原始数据长度: %d, 清理后长度: %d\n', length(data_with_nan), length(data_cleaned)); % 或者,用中位数填充NaN(一种稳健方法) data_filled = fillmissing(data_with_nan, 'constant', median(data_with_nan, 'omitnan'));

描述性统计是数据分析的基石,也是避免后续建模分析“失之毫厘,谬以千里”的关键一步。在MATLAB中,这些计算虽然简单,但背后的选择和解读却需要经验和思考。养成从多个维度(集中趋势、离散程度、分布形状)审视数据的习惯,结合可视化工具,你就能在数据海洋中迅速定位关键信息,为更深度的分析打下坚实的基础。我个人在实际操作中,通常会将这些统计量和图形整合到一个自动生成的报告中,作为任何数据分析项目的第一页,这能极大地提升与团队或客户沟通的效率和专业性。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询