
本文旨在深入解析 SciPy 库中 `scipy.stats.trim_mean` 函数的工作原理,特别是其 `proportiontocut` 参数如何影响截断行为。我们将澄清 `trim_mean` 是基于样本观测值的比例进行截断,而非基于统计百分位数,并通过代码示例演示其在不同截断比例下的具体表现,并对比手动实现百分位数截断的方法,帮助读者避免常见误解。
截断均值(Trimmed Mean),又称修剪均值或切尾均值,是一种统计量,旨在通过移除数据集两端的极端值来提高均值的稳健性。它通常用于处理含有异常值的数据集,以获得一个更能代表数据中心趋势的估计。在统计学中,截断均值通常定义为在排序后的数据集中,移除一定比例(或固定数量)的最小和最大值后,对剩余数据计算的均值。
scipy.stats.trim_mean 函数是 SciPy 库提供的一个实现截断均值的工具。其核心参数 proportiontocut 定义了从数据两端各截去的观测值比例。然而,一个常见的误解是,这个比例是基于数据的统计百分位数来截断的。实际上,trim_mean 的截断机制是基于样本观测值的数量。
具体来说,proportiontocut 表示从排序后的数据集的两端各移除的观测值占总观测值数量的比例。函数会计算需要移除的观测值数量:num_to_cut = proportiontocut * len(data)。关键在于,如果这个计算结果不是整数,scipy.stats.trim_mean 会向下取整,这意味着它会截去小于或等于计算结果的整数个观测值。文档中明确指出:“如果比例导致非整数切片索引,则切片的数量会减少。”
让我们通过一个具体的例子来理解这一点。
示例 1:非整数截断比例的边缘效应
考虑一个包含 9 个数据点的数据集 data = [1, 2, 2, 3, 4, 30, 4, 4, 5],并尝试使用 trim_percentage = 0.05 (即 5%) 进行截断。
from scipy.stats import trim_mean
import numpy as np
data = [1, 2, 2, 3, 4, 30, 4, 4, 5]
# 对数据进行排序,尽管trim_mean内部会处理,但为了理解清晰,手动排序
sorted_data = sorted(data)
print(f"原始排序数据: {sorted_data}")
trim_percentage = 0.05 # 从两端各截去 5%
result = trim_mean(data, trim_percentage)
print(f"使用 trim_mean({trim_percentage}) 的结果 = {result}")
# 计算应截去的观测值数量
num_observations = len(data)
num_to_cut_per_side = trim_percentage * num_observations
print(f"每端应截去的观测值数量 (理论值): {num_to_cut_per_side}")
# 实际截去的观测值数量(向下取整)
actual_cut_per_side = int(num_to_cut_per_side)
print(f"每端实际截去的观测值数量 (向下取整): {actual_cut_per_side}")
# 如果实际截去数量为0,则结果应与原始均值相同
mean_original = np.mean(data)
print(f"原始数据均值: {mean_original}")输出结果:
率先引入语言包机制,可在1小时内制作出任何语言版本,程序所有应用文字皆引自LANG目录下的语言包文件,独特的套图更换功能,三级物品分类,购物车帖心设计,在国内率先将购物车与商品显示页面完美结合,完善的商品管理,具备上架、下架缺货及特价商品设置功能多多,商城名、消费税、最低购物金额、货币符号、商城货币名称全部后台设定,多级用户考虑,管理员只需要设置用户级别、不同级别用户之返点系统自动判断用户应得返还
0
原始排序数据: [1, 2, 2, 3, 4, 4, 4, 5, 30] 使用 trim_mean(0.05) 的结果 = 6.111111111111111 每端应截去的观测值数量 (理论值): 0.45 每端实际截去的观测值数量 (向下取整): 0 原始数据均值: 6.111111111111111
从上述结果可以看出,当 trim_percentage 为 0.05 时,对于 9 个数据点,每端应截去的观测值数量为 0.05 * 9 = 0.45。由于 trim_mean 会向下取整,实际每端截去的观测值数量为 0。因此,函数返回的结果就是原始数据集的均值,没有任何观测值被移除。
示例 2:当截断比例刚好超过阈值时
为了验证上述行为,我们可以调整 proportiontocut,使其刚好超过能截去至少一个观测值的阈值。对于 9 个数据点,要截去每端一个观测值,proportiontocut 必须大于 1/9。
from scipy import stats
import numpy as np
x = [1, 2, 2, 3, 4, 30, 4, 4, 5]
sorted_x = sorted(x)
print(f"原始排序数据: {sorted_x}")
p_threshold = 1 / len(x) # 截去一个观测值所需的最小比例
print(f"截去一个观测值所需的比例阈值: {p_threshold:.4f}")
eps = 1e-15 # 一个非常小的正数
# 比例略小于阈值时
result_below_threshold = stats.trim_mean(x, p_threshold - eps)
print(f"当 proportiontocut = {p_threshold - eps:.4f} 时 (略小于阈值): {result_below_threshold}")
# 比例略大于阈值时
result_above_threshold = stats.trim_mean(x, p_threshold + eps)
print(f"当 proportiontocut = {p_threshold + eps:.4f} 时 (略大于阈值): {result_above_threshold}")
# 手动计算截去一个观测值后的均值
# 截去最小的 1 和最大的 30
trimmed_manually = sorted_x[1:-1] # 移除第一个和最后一个元素
print(f"手动截去一个观测值后的数据: {trimmed_manually}")
print(f"手动截去一个观测值后的均值: {np.mean(trimmed_manually)}")输出结果:
原始排序数据: [1, 2, 2, 3, 4, 4, 4, 5, 30] 截去一个观测值所需的比例阈值: 0.1111 当 proportiontocut = 0.1111 时 (略小于阈值): 6.111111111111111 当 proportiontocut = 0.1111 时 (略大于阈值): 3.4285714285714284 手动截去一个观测值后的数据: [2, 2, 3, 4, 4, 4, 5] 手动截去一个观测值后的均值: 3.4285714285714284
这个例子清晰地表明,一旦 proportiontocut 超过了 1/len(data),trim_mean 就会从两端各截去一个观测值。截去 1 和 30 后,剩余数据为 [2, 2, 3, 4, 4, 4, 5],其均值为 3.428571...,这与 trim_mean 在 p_threshold + eps 时的结果一致。
用户最初的困惑在于,他们预期 trim_mean 会像基于百分位数那样进行截断,即移除低于第 5 百分位数和高于第 95 百分位数的数据。这种方法与 trim_mean 的基于观测值数量的截断是不同的概念。
百分位数截断的实现
如果需要基于百分位数来截断数据,则需要手动实现。以下是一个使用 NumPy 实现百分位数截断的示例:
import numpy as np
data = [1, 2, 2, 3, 4, 30, 4, 4, 5]
percentile_lower = 5 # 5th percentile
percentile_upper = 95 # 95th percentile
# 计算第 5 和第 95 百分位数
p5, p95 = np.percentile(data, [percentile_lower, percentile_upper])
print(f"第 {percentile_lower} 百分位数 = {p5}")
print(f"第 {percentile_upper} 百分位数 = {p95}")
# 过滤掉落在百分位数之外的数据
trimmed_by_percentile = [x for x in data if p5 < x < p95]
print(f"按百分位数截断后的数据: {trimmed_by_percentile}")
# 计算截断后的均值
if trimmed_by_percentile:
mean_by_percentile = np.mean(trimmed_by_percentile)
print(f"按百分位数截断后的均值 = {mean_by_percentile}")
else:
print("按百分位数截断后没有剩余数据。")输出结果:
第 5 百分位数 = 1.4 第 95 百分位数 = 19.999999999999993 按百分位数截断后的数据: [2, 2, 3, 4, 4, 5] 按百分位数截断后的均值 = 3.3333333333333335
在这个例子中,第 5 百分位数是 1.4,第 95 百分位数是 19.99...。因此,原始数据中的 1 和 30 都被移除了(因为 1 小于 1.4,30 大于 19.99...)。最终计算出的均值是 3.333...。这与 scipy.stats.trim_mean 的结果明显不同,因为它们采用了不同的截断策略。
scipy.stats.trim_mean 基于观测值数量截断:
百分位数截断是不同的概念:
选择合适的截断方法:
理解 scipy.stats.trim_mean 的精确行为对于正确应用截断均值至关重要,尤其是在处理小数据集或需要精细控制截断逻辑的场景中。
以上就是深入理解 SciPy trim_mean 的截断机制与应用的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号