4. 描述性统计分析:集中趋势、离散程度与分布形态
大家好,我是老张。今天咱们聊聊测试数据分析里最基础、也最实用的一块——描述性统计。说白了,就是拿到一堆测试数据后,怎么用几个数字快速描述出这堆数据的“脾气秉性”。
你想想看,每次跑完一轮测试,日志里成千上万条数据。光靠肉眼扫,根本看不出门道。这时候就需要描述性统计登场了。我个人习惯,拿到数据第一件事,就是算这三个维度:集中趋势、离散程度、分布形态。
4.1 集中趋势:数据都往哪儿聚?
集中趋势,就是回答一个问题:“这批数据,大概在什么位置?” 常用的指标有三个:均值、中位数、众数。
4.1.1 均值(Mean)
均值就是算术平均数。大家都会算,但我要说的是——均值很脆弱。我在项目中遇到过,一个接口的响应时间,99%的请求都在50ms以内,突然有一次超时到了10秒。均值一下子从48ms飙到了150ms。你看,一个异常点就把均值带偏了。
所以,均值适合数据比较“干净”、没有极端值的情况。比如CPU使用率,一般波动不大,用均值就很靠谱。
import numpy as np
response_times = [45, 48, 52, 47, 10000, 46, 49, 51, 44, 50]
mean_value = np.mean(response_times)
print(f"均值: {mean_value:.2f} ms") # 输出: 均值: 1053.20 ms
4.1.2 中位数(Median)
中位数,就是把数据从小到大排好,取中间那个数。它不怕极端值。刚才那个例子,用中位数看看:
median_value = np.median(response_times)
print(f"中位数: {median_value:.2f} ms") # 输出: 中位数: 48.50 ms
你看,中位数稳稳地停在48.5ms,这才是大多数请求的真实表现。我建议,在分析响应时间、延迟这类数据时,优先看中位数。它比均值更能反映“大多数用户的体验”。
4.1.3 众数(Mode)
众数,就是出现次数最多的那个值。在测试数据里,众数能帮我们发现“最常见的状态”。比如,分析错误码分布时,众数告诉你哪个错误码出现得最频繁。
from scipy import stats
error_codes = [200, 200, 404, 500, 200, 404, 200, 200, 503, 200]
mode_result = stats.mode(error_codes)
print(f"众数: {mode_result.mode[0]}, 出现次数: {mode_result.count[0]}")
4.2 离散程度:数据到底有多散?
集中趋势告诉你数据在哪儿,离散程度告诉你数据“散不散”。两个系统,平均响应时间都是50ms,但一个波动在±5ms,另一个波动在±50ms。体验能一样吗?
4.2.1 极差(Range)
极差 = 最大值 - 最小值。最简单粗暴的离散指标。但它只看两头,中间的数据波动它不管。我曾经用它快速判断一次压测有没有“毛刺”——如果极差突然变大,大概率有异常。
data_range = np.max(response_times) - np.min(response_times)
print(f"极差: {data_range} ms")
4.2.2 方差与标准差(Variance & Standard Deviation)
方差,衡量每个数据与均值的平均偏离程度。标准差是方差的平方根,单位跟原始数据一致,更好理解。
嗯,这里要注意:标准差越小,数据越稳定;标准差越大,数据越“暴躁”。我在做稳定性测试时,特别喜欢看标准差。如果一个模块的内存占用标准差突然变大,说明内存管理可能出了问题。
variance = np.var(response_times, ddof=1) # 样本方差
std_dev = np.std(response_times, ddof=1) # 样本标准差
print(f"方差: {variance:.2f}, 标准差: {std_dev:.2f}")
4.3 分布形态:数据长什么样?
光知道位置和离散程度还不够。数据是“左偏”还是“右偏”?是“尖峰”还是“平顶”?这就要看偏度和峰度了。
4.3.1 偏度(Skewness)
偏度衡量数据分布的不对称性。
- 偏度 = 0:对称分布,比如正态分布。
- 偏度 > 0:右偏(正偏),尾巴在右边。说明有少量很大的值把均值拉高了。
- 偏度 < 0:左偏(负偏),尾巴在左边。说明有少量很小的值把均值拉低了。
我记得有一次分析数据库查询耗时,偏度值高达3.2。一看数据,果然有几个大查询拖了后腿。这就是典型的右偏分布。
skewness = stats.skew(response_times)
print(f"偏度: {skewness:.2f}")
4.3.2 峰度(Kurtosis)
峰度衡量数据分布的“尖峭”程度。它告诉我们数据是集中在均值附近,还是分散在两边。
- 峰度 ≈ 0:正态分布的峰度(通常用超额峰度,正态分布为0)。
- 峰度 > 0:尖峰分布。数据集中在均值附近,尾部较厚。说明异常值可能更多。
- 峰度 < 0:平峰分布。数据比较分散,没有明显的集中趋势。
为什么关心峰度?因为峰度高,意味着“极端事件”发生的概率比正态分布预测的要高。做容量规划时,这个指标很关键。
kurtosis = stats.kurtosis(response_times, fisher=True) # Fisher定义,正态分布为0
print(f"峰度: {kurtosis:.2f}")
4.4 综合案例:一次接口压测的数据分析
好了,理论讲完了。咱们来一个真实的场景。假设你刚跑完一轮接口压测,拿到了1000个响应时间数据。你会怎么做?
我的习惯是,先算这几个指标:
| 指标 | 值 | 解读 |
|---|---|---|
| 均值 | 52.3 ms | 平均响应时间 |
| 中位数 | 48.1 ms | 大多数用户的体验 |
| 标准差 | 15.6 ms | 波动范围,越小越稳定 |
| 偏度 | 1.8 | 右偏,存在少量慢请求 |
| 峰度 | 4.2 | 尖峰,异常值比预期多 |
看到这个结果,我会立刻去查那部分“慢请求”的日志。偏度1.8说明问题不大,但峰度4.2提醒我——这些慢请求不是偶然,背后可能有规律。我曾经就靠这个思路,发现了一个连接池泄漏的问题。
好了,这一章就到这里。下一章咱们聊聊“推断性统计”,看看怎么从样本数据推断整体情况。到时候见。