在Pandas数据分析场景中,直接计算列的均值容易受到极端异常值的影响,通过限定指定百分位范围筛选有效数据后再计算均值,能得到更贴合真实分布的结果。这种处理方式在金融数据、用户行为数据等存在长尾分布的场景中使用非常广泛。

核心实现思路
整个计算流程可以分为三个核心步骤:首先计算目标列的上下百分位阈值,然后根据阈值筛选落在范围内的数据,最后对筛选后的数据计算列均值。整个过程可以结合Pandas和numpy的相关函数高效完成。
步骤1:计算百分位阈值
使用numpy的percentile函数可以计算指定列的对应百分位数值,比如要计算10%和90%的阈值,分别传入对应的百分位参数即可。
步骤2:筛选范围内的数据
通过Pandas的布尔索引功能,筛选出列值大于等于下阈值且小于等于上阈值的数据行,排除超出范围的异常值。
步骤3:计算筛选后数据的列均值
对筛选后的DataFrame直接调用mean方法,即可得到指定百分位范围内的列均值。
完整代码示例
以下示例模拟了一份包含100条随机数据的DataFrame,计算数值列在10%到90%百分位范围内的均值:
import pandas as pd
import numpy as np
# 构造示例数据
np.random.seed(42)
data = {
'value': np.random.normal(loc=100, scale=20, size=100), # 正态分布数据,存在少量极端值
'category': np.random.choice(['A', 'B', 'C'], size=100)
}
df = pd.DataFrame(data)
# 定义百分位范围,这里取10%到90%
lower_percentile = 10
upper_percentile = 90
# 计算上下阈值
lower_threshold = np.percentile(df['value'], lower_percentile)
upper_threshold = np.percentile(df['value'], upper_percentile)
print(f"下阈值({lower_percentile}%): {lower_threshold:.2f}")
print(f"上阈值({upper_percentile}%): {upper_threshold:.2f}")
# 筛选范围内的数据
filtered_df = df[(df['value'] >= lower_threshold) & (df['value'] <= upper_threshold)]
# 计算范围内的列均值
range_mean = filtered_df['value'].mean()
print(f"指定百分位范围内的列均值: {range_mean:.2f}")
# 对比全量数据的均值
full_mean = df['value'].mean()
print(f"全量数据的列均值: {full_mean:.2f}")
多列批量计算场景
如果需要同时对多个数值列计算指定百分位范围内的均值,可以封装成通用函数,提升代码复用性:
def calc_percentile_range_mean(df, columns, lower=10, upper=90):
"""
计算DataFrame指定列在百分位范围内的均值
:param df: 输入的Pandas DataFrame
:param columns: 需要计算的列名列表
:param lower: 下百分位,默认10
:param upper: 上百分位,默认90
:return: 包含各列均值的Series
"""
result = {}
for col in columns:
# 跳过非数值列
if not pd.api.types.is_numeric_dtype(df[col]):
continue
lower_threshold = np.percentile(df[col], lower)
upper_threshold = np.percentile(df[col], upper)
filtered_col = df[col][(df[col] >= lower_threshold) & (df[col] <= upper_threshold)]
result[col] = filtered_col.mean()
return pd.Series(result)
# 新增一个测试列
df['score'] = np.random.randint(0, 100, size=100)
# 批量计算多列的百分位范围均值
multi_col_mean = calc_percentile_range_mean(df, ['value', 'score'], lower=20, upper=80)
print("多列百分位范围均值结果:")
print(multi_col_mean)
注意事项
- 百分位参数的取值范围是0到100,传入超出范围的数值会触发报错,使用前需要做好参数校验。
- 如果目标列存在缺失值,
np.percentile函数会返回nan,建议先计算阈值前用dropna处理缺失值。 - 对于分类数据不需要计算百分位均值,函数封装时需要做好数值类型的判断,避免无效计算。
这种基于百分位范围筛选后计算均值的方法,本质是截断异常值的处理方式,适合大部分存在轻度异常值的数据集,若数据存在大量极端值,可能需要结合其他异常值处理方法共同使用。