我目前正在开展一个数据分析项目,在该项目中,我使用 Z 分数来检测数据集数值列中的异常值。但是,我遇到了一个问题,合法的数据点被标记为异常值,我不确定为什么会发生这种情况。
这就是我正在做的:
缺失值的插补:我使用 IterativeImputer sklearn.impute 填充数字列中的缺失值。 离群值检测:我计算每个数值列的 Z 分数,以使用阈值 3 检测离群值。 例如,我有一个埃及希腊罗马摔跤手 Yasser Abdel Rahman Sakr 的记录,其属性如下:
体重:120 公斤 身高: 180 厘米 尽管这些测量结果是合理的,但该记录被我的代码标记为异常值。其他记录也出现此问题。
以下是我的代码的相关部分:
import numpy as np
import pandas as pd
from sklearn.impute import IterativeImputer
# Assuming 'data' is already defined and loaded
numeric_cols = data.select_dtypes(include=['float64', 'int64']).columns
categorical_cols = data.select_dtypes(include=['object']).columns
# Impute missing values in numeric columns
mice_imputer = IterativeImputer(max_iter=10, random_state=0)
df_numeric = pd.DataFrame(mice_imputer.fit_transform(data[numeric_cols]), columns=numeric_cols)
# Combine imputed numeric columns with original categorical columns
df_MICE = pd.concat([df_numeric, data[categorical_cols]], axis=1)
# Dictionary to store outlier information
outliers_info = {}
for col in numeric_cols:
# Calculate mean and standard deviation
mean = df_MICE[col].mean()
std_dev = df_MICE[col].std()
# Avoid division by zero if std_dev is zero
if std_dev == 0:
print(f"Standard deviation is zero for column {col}. Skipping outlier detection.")
continue
# Calculate Z-scores
z_scores = (df_MICE[col] - mean) / std_dev
# Define outlier threshold
threshold = 3
# Find outliers
outliers = df_MICE[np.abs(z_scores) > threshold]
# Store the number of outliers and a sample of outliers in the dictionary
outliers_info[col] = {
'count': len(outliers),
'sample': outliers.head(1) # Sample of one outlier
}
# Print the number of outliers and a sample for each numerical column
for col, info in outliers_info.items():
print(f'Column: {col}')
print(f'Number of outliers: {info["count"]}')
if info['count'] > 0:
print('Sample outlier:')
print(info['sample'])
else:
print('No outliers.')
print() # Print a blank line for better readability
问题:
尽管是真实且合理的记录,但 Yasser Abdel Rahman Sakr 的体重和身高被标记为异常值。其他记录也会出现此问题。
问题:
什么可能导致合法数据点被标记为异常值? 在这种情况下是否有任何改进或替代方法可以更好地处理异常值检测? 我是否应该考虑其他因素或异常值检测方法? 感谢您提供的任何指导或建议。
谢谢!
发现的问题很常见:在使用 Z 分数等技术时,完全合法的数据点有时会被标记为异常值。以下是可能发生这种情况的原因,以及在的场景中可以考虑的改进和替代方案:
1. 异常值检测方法的局限性
- Z 分数对异常值的敏感性: Z 分数高度依赖于均值和标准差,而均值和标准差很容易受到异常值的影响。当的数据集中存在极端值时,它会导致均值和标准差出现偏差,从而导致合法数据点被标记为异常值。
- 数据分布的假设: Z 分数假设的数据呈正态分布。如果的数据不呈正态分布,则使用 Z 分数可能会导致异常值识别不准确。
2. 数据集的特定特征
- 小数据集: 在较小的数据集中,单个异常值会对均值和标准差产生重大影响,从而使 Z 分数方法更容易出现错误。
- 真实异常值的存在: 提到的 Yasser Abdel Rahman Sakr 的例子说明了这一点,即使在摔跤手等群体中,他的体重和身高也可能被认为是异常的。这凸显了上下文在异常值检测中的重要性。
改进和替代方案
-
稳健的异常值检测方法
-
四分位距 (IQR): IQR 是一种基于数据四分位数的稳健统计量度。它对异常值的影响较小。可以使用 IQR 方法通过将高于第三个四分位数 1.5 倍 IQR 或低于第一个四分位数 1.5 倍 IQR 的值标识为异常值来检测异常值。
-
中位数绝对偏差 (MAD): MAD 是数据点与其中位数之间绝对偏差的中位数。它对异常值具有很强的鲁棒性。
-
考虑数据分布
-
数据转换: 如果的数据不呈正态分布,请尝试使用对数转换或 Box-Cox 转换等技术对数据进行转换。这可以帮助使数据更接近正态分布,从而提高 Z 分数的可靠性。
-
非参数方法: 考虑使用非参数异常值检测方法,这些方法不假设数据呈特定分布。示例包括基于密度的局部异常值因子 (LOF) 和单类支持向量机 (OCSVM)。
-
上下文和领域知识
-
定义阈值: 不要盲目地依赖于诸如 3 之类的任意阈值,而是根据对数据的理解和问题的上下文来设置有意义的阈值。
- 审查标记的异常值: 始终手动审查标记为异常值的数据点,以确定它们是否确实是错误的,或者它们是否代表数据集中有趣的真实异常值。
的代码的改进
- 实现 IQR 方法:
def find_outliers_iqr(df, col):
"""使用 IQR 方法查找给定 DataFrame 列中的异常值。
"""
q1 = df[col].quantile(0.25)
q3 = df[col].quantile(0.75)
iqr = q3 - q1
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr
outliers = df[(df[col] < lower_bound) | (df[col] > upper_bound)]
return outliers
# 针对每个数字列检测异常值
for col in numeric_cols:
outliers = find_outliers_iqr(df_MICE, col)
if len(outliers) > 0:
outliers_info[col] = {
'count': len(outliers),
'sample': outliers.head(1)
}
else:
outliers_info[col] = {
'count': 0,
'sample': None
}
- 探索数据转换和非参数方法,以便在 IQR 方法仍然产生太多误报时获得更准确的异常值检测。
请记住,没有一种放之四海而皆准的异常值检测方法。最有效的方法将取决于的特定数据集和问题的上下文。通过探索不同的方法、了解它们的优缺点,并结合领域知识,可以最大限度地提高准确识别真正异常值的可能性。
标签:python,machine-learning,scikit-learn From: 78845677