使用Z-Score移除pandas数据框异常值,处理百分比变化后得空数据框?
问题根源和解决方案
先给你说清楚为啥用pct_change()后跑z-score会得到空数据框:
pct_change()生成的第一行是NaN(因为没有前一行数据计算变化率),stats.zscore()碰到NaN会返回NaN,而NaN < 1.5的结果是False,这行直接被过滤。- 如果原始数据里有0或者极小值,计算百分比变化时会出现极大值甚至无穷大(比如从0涨到0.1,变化率是无穷大),这些值的z-score会大到离谱,远超过你设置的任何阈值,导致所有行的条件
np.abs(stats.zscore(df[0])) < 1.5都不满足,最后就得到空数据框。
解决步骤
1. 先清理NaN和无穷值
先把pct_change()产生的无效值处理掉:
import pandas as pd import numpy as np from scipy import stats # 模拟你的原始数据 df = pd.DataFrame(np.random.randn(100, 3)) # 计算百分比变化 df_pct = df.pct_change() # 替换无穷大值为NaN,再删掉所有包含NaN的行 df_pct_clean = df_pct.replace([np.inf, -np.inf], np.nan).dropna()
2. 用更稳健的方法过滤异常值(替代z-score)
z-score基于均值和标准差,对极端值特别敏感,而百分比变化数据本身就容易出极端值,建议用中位数绝对偏差(MAD),它对异常值的耐受力更强:
def mad_based_outlier(data, threshold=3.5): median = np.median(data) mad = np.median(np.abs(data - median)) modified_z_score = 0.6745 * (data - median) / mad return np.abs(modified_z_score) > threshold # 对第一列过滤异常值(~表示取反,保留非异常值) df_filtered = df_pct_clean[~mad_based_outlier(df_pct_clean[0])]
如果非要用z-score,得先把极端的超大值提前过滤,再调整阈值(效果不如MAD稳定):
# 先去掉变化率绝对值超过合理范围的行(比如>10,根据你的数据调整) df_pct_clean = df_pct_clean[np.abs(df_pct_clean[0]) < 10] # 再用z-score过滤 df_filtered = df_pct_clean[np.abs(stats.zscore(df_pct_clean[0])) < 3]
3. 验证结果
跑代码后可以查看过滤后的数据规模:
print(df_filtered.shape)
内容的提问来源于stack exchange,提问作者prashanth manohar
相关产品推荐
相关产品推荐

