程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

数据异常值检测方法汇总and异常值处理

balukai 2025-01-21 15:07:15 文章精选 5 ℃

昨天介绍了数据的标准化处理方法《数据标准化(归一化)》,里面介绍了常见的方法。而且数据里面有异常值的情况下不同方法的作用性也不一样。今天就来详细介绍一下数据异常值的检测方法,以及如何处理异常值。

异常值检测与处理是数据清洗过程中的一个关键步骤,它涉及到识别和处理那些与大多数数据显著不同的数据点。异常值可能是由于数据录入错误、测量误差、数据损坏或其他原因造成的。处理异常值的目的是提高数据的质量,避免它们对分析结果产生不利影响。以下是异常值检测与处理的详细介绍。

【异常值检测】

整体分成6类13中方法来进行异常值的检测,目录如下↓

下面分别介绍一下每一种方法,然后通过正态分布和非正态分布两种数据进行演示,先把数据生成一下,代码和结果如下↓

import numpy as np
import matplotlib.pyplot as plt
from sklearn.neighbors import LocalOutlierFactor
from sklearn.cluster import DBSCAN
from sklearn.ensemble import IsolationForest
from sklearn.svm import OneClassSVM
from sklearn.decomposition import PCA
from scipy import stats
from sklearn.mixture import GaussianMixture
# 生成正态分布和非正态分布数据集
np.random.seed(21)
X_normal = np.random.normal(loc=0, scale=3, size=100)
X_uniform = np.random.uniform(low=-5, high=5, size=100)
# 添加异常值
X_normal_with_outliers = np.append(X_normal, [10, 15, -10, -15])
X_uniform_with_outliers = np.append(X_uniform, [10, 15, -10, -15])
# 可视化函数
def plot_data(X, outliers, title):
    plt.figure(figsize=(10, 6))
    plt.scatter(range(len(X)), X, edgecolor='k', s=20, label='Data')
    plt.scatter(outliers, X[outliers], color='red', edgecolor='k', s=50, label='Outliers')
    plt.title(title)
    plt.legend()
    plt.show()

绘制图形↓

plt.hist(X_normal_with_outliers.flatten(), bins=50, color='blue', alpha=0.7)
plt.hist(X_uniform_with_outliers.flatten(), bins=30, color='green', alpha=0.7)

【统计方法-标准差法】

也称3σ准则,假设数据符合正态分布,通过计算均值和标准差,将超过均值±3倍标准差的值视为异常值。优点是简单易行,适用于正态分布的数据。缺点是对非正态分布的数据效果较差,对极端值敏感。

def detect_outliers_std(X):
    mean = np.mean(X)
    std = np.std(X)
    outliers = np.where((X > mean + 3 * std) | (X < mean - 3 * std))
    return outliers


outliers_std_normal = detect_outliers_std(X_normal_with_outliers)
outliers_std_uniform = detect_outliers_std(X_uniform_with_outliers)


plot_data(X_normal_with_outliers, outliers_std_normal[0], 'Standard Deviation Method -正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_std_uniform[0], 'Standard Deviation Method -非正态分布+异常值')


【统计方法-Z-Score法】

标准化数据,根据Z值(通常±3)来检测异常值。优点是与标准差法类似,适用于正态分布的数据。缺点是同样对非正态分布的数据效果较差。

def detect_outliers_zscore(X):
    z_scores = np.abs(stats.zscore(X))
    outliers = np.where(z_scores > 3)
    return outliers
outliers_zscore_normal = detect_outliers_zscore(X_normal_with_outliers)
outliers_zscore_uniform = detect_outliers_zscore(X_uniform_with_outliers)
plot_data(X_normal_with_outliers, outliers_zscore_normal[0], 'Z-Score Method - 正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_zscore_uniform[0], 'Z-Score Method - 非正态分布+异常值')

【统计方法-箱线图法】

使用四分位数(Q1和Q3)和四分位距(IQR),超过Q1-1.5倍IQR或Q3+1.5倍IQR的值视为异常值。优点是适用于任何分布的数据,对数据分布的要求较低。缺点是对异常值比例较高的数据效果不佳。

def detect_outliers_iqr(X):
    Q1 = np.percentile(X, 25)
    Q3 = np.percentile(X, 75)
    IQR = Q3 - Q1
    outliers = np.where((X < Q1 - 1.5 * IQR) | (X > Q3 + 1.5 * IQR))
    return outliers
outliers_iqr_normal = detect_outliers_iqr(X_normal_with_outliers)
outliers_iqr_uniform = detect_outliers_iqr(X_uniform_with_outliers)
plot_data(X_normal_with_outliers, outliers_iqr_normal[0], 'IQR Method - 正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_iqr_uniform[0], 'IQR Method - 非正态分布+异常值')

【基于距离的方法-K-最近邻】

KNN,计算每个数据点与其最近的k个邻居的距离,显著大于其他点的距离则为异常值。优点是无需对数据分布有假设,适用于多维数据。缺点是计算复杂度较高,参数k的选择较敏感。

def detect_outliers_knn(X, k=3):
    clf = LocalOutlierFactor(n_neighbors=k)
    y_pred = clf.fit_predict(X.reshape(-1, 1))
    outliers = np.where(y_pred == -1)
    return outliers
outliers_knn_normal = detect_outliers_knn(X_normal_with_outliers)
outliers_knn_uniform = detect_outliers_knn(X_uniform_with_outliers)
plot_data(X_normal_with_outliers, outliers_knn_normal[0], 'KNN Method - 正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_knn_uniform[0], 'KNN Method - 非正态分布+异常值')



【基于距离的方法-局部离群因子】

LOF,比较一个点与其邻居的局部密度,检测局部异常值。优点是能够检测局部异常值,适用于多维数据。缺点是参数选择较为复杂,计算复杂度较高。

def detect_outliers_lof(X, n_neighbors=20):
    clf = LocalOutlierFactor(n_neighbors=n_neighbors)
    y_pred = clf.fit_predict(X.reshape(-1, 1))
    outliers = np.where(y_pred == -1)
    return outliers
outliers_lof_normal = detect_outliers_lof(X_normal_with_outliers)
outliers_lof_uniform = detect_outliers_lof(X_uniform_with_outliers)
plot_data(X_normal_with_outliers, outliers_lof_normal[0], 'LOF Method - 正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_lof_uniform[0], 'LOF Method - 非正态分布+异常值')

【基于密度的方法-DBSCAN】

基于密度的聚类方法,找到密度较低的区域来识别异常值。优点是能找到任意形状的聚类,适用于空间密度不均匀的数据。缺点是参数选择较为复杂,对高维数据效果较差。

def detect_outliers_dbscan(X, eps=0.5, min_samples=5):
    clf = DBSCAN(eps=eps, min_samples=min_samples)
    y_pred = clf.fit_predict(X.reshape(-1, 1))
    outliers = np.where(y_pred == -1)
    return outliers
outliers_dbscan_normal = detect_outliers_dbscan(X_normal_with_outliers)
outliers_dbscan_uniform = detect_outliers_dbscan(X_uniform_with_outliers)
plot_data(X_normal_with_outliers, outliers_dbscan_normal[0], 'DBSCAN Method - 正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_dbscan_uniform[0], 'DBSCAN Method - 非正态分布+异常值')

【基于模型的方法-孤立森林】

Isolation Forest,基于随机森林的思想,构建多棵树,通过分裂的次数来衡量异常值。优点是适用于大数据集,对数据分布无假设。缺点是参数调优复杂,对小数据集效果不佳。

def detect_outliers_isolation_forest(X):
    clf = IsolationForest(contamination=0.05)
    y_pred = clf.fit_predict(X.reshape(-1, 1))
    outliers = np.where(y_pred == -1)
    return outliers
outliers_isolation_normal = detect_outliers_isolation_forest(X_normal_with_outliers)
outliers_isolation_uniform = detect_outliers_isolation_forest(X_uniform_with_outliers)
plot_data(X_normal_with_outliers, outliers_isolation_normal[0], 'Isolation Forest Method - 正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_isolation_uniform[0], 'Isolation Forest Method - 非正态分布+异常值')



【基于模型的方法-一类支持向量机】

One-Class SVM,构建一个边界来识别异常值。优点是适用于高维数据,对数据分布无假设。缺点是计算复杂度高,对参数敏感。

def detect_outliers_one_class_svm(X):
    clf = OneClassSVM(nu=0.05, kernel='rbf', gamma=0.1)
    y_pred = clf.fit_predict(X.reshape(-1, 1))
    outliers = np.where(y_pred == -1)
    return outliers
outliers_one_class_svm_normal = detect_outliers_one_class_svm(X_normal_with_outliers)
outliers_one_class_svm_uniform = detect_outliers_one_class_svm(X_uniform_with_outliers)
plot_data(X_normal_with_outliers, outliers_one_class_svm_normal[0], 'One-Class SVM Method - 正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_one_class_svm_uniform[0], 'One-Class SVM Method - 非正态分布+异常值')


【基于回归的方法-残差分析】

利用回归模型,分析残差,如果残差值过大,则可能是异常值。优点是结合了回归分析,适用于时间序列数据。缺点是依赖于模型的准确性,适用于线性关系的数据。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
# 生成线性数据集
np.random.seed(42)
X = np.arange(100)
y = 3 * X + 7 + np.random.normal(0, 10, size=X.shape)
# 添加异常值
X_with_outliers = np.append(X, [20, 50, 80])
y_with_outliers = np.append(y, [1000, -1000, 500])
# 基于回归方法的异常值检测 - 残差分析
def detect_outliers_residual_analysis(X, y):
    X = X.reshape(-1, 1)
    model = LinearRegression()
    model.fit(X, y)
    predictions = model.predict(X)
    residuals = y - predictions
    residual_std = np.std(residuals)
    residual_mean = np.mean(residuals)
    outliers = np.where(np.abs(residuals) > 3 * residual_std)
    return outliers
# 检测数据集中的异常值
outliers_residual = detect_outliers_residual_analysis(X_with_outliers, y_with_outliers)
# 可视化原始数据和异常值
plt.figure(figsize=(10, 6))
plt.scatter(X_with_outliers, y_with_outliers, edgecolor='k', s=20, label='Data')
plt.scatter(X_with_outliers[outliers_residual], y_with_outliers[outliers_residual], color='red', edgecolor='k', s=50, label='Outliers')
plt.plot(X, 3 * X + 7, color='blue', linewidth=2, label='True Function')
plt.title('Residual Analysis Method (with Outliers)')
plt.legend()
plt.show()

【其他方法-主成分分析】

PCA,通过降维,分析主成分,找出在主成分空间中偏离较远的数据点。优点是降维后检测异常值,适用于多维数据。缺点是解释性较差,适用于线性关系的数据。

def detect_outliers_pca(X, n_components=1):
    pca = PCA(n_components=n_components)
    X_pca = pca.fit_transform(X.reshape(-1, 1))
    outliers = detect_outliers_zscore(X_pca)
    return outliers
outliers_pca_normal = detect_outliers_pca(X_normal_with_outliers)
outliers_pca_uniform = detect_outliers_pca(X_uniform_with_outliers)
plot_data(X_normal_with_outliers, outliers_pca_normal[0], 'PCA Method - 正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_pca_uniform[0], 'PCA Method - 非正态分布+异常值')


【其他方法-高斯混合模型】

GMM,假设数据由多个高斯分布组成,找出概率较低的点。优点是适用于复杂分布的数据。缺点是计算复杂度较高,需选择适当的分布数量。

def detect_outliers_gmm(X, n_components=1):
    gmm = GaussianMixture(n_components=n_components, covariance_type='full')
    gmm.fit(X.reshape(-1, 1))
    scores = gmm.score_samples(X.reshape(-1, 1))
    threshold = np.percentile(scores, 5)
    outliers = np.where(scores < threshold)
    return outliers
outliers_gmm_normal = detect_outliers_gmm(X_normal_with_outliers, n_components=1)
outliers_gmm_uniform = detect_outliers_gmm(X_uniform_with_outliers, n_components=1)
plot_data(X_normal_with_outliers, outliers_gmm_normal[0], 'GMM Method - 正态分布+异常值')
plot_data(X_uniform_with_outliers, outliers_gmm_uniform[0], 'GMM Method - 非正态分布+异常值')

下面是一些建议,根据需要检测数据的维度不同,可以选择不同的检验方法。

一维数据建议:标准差法,箱线图法(IQR法),Z-Score法;

二维数据建议:残差分析,K-最近邻(KNN),局部离群因子(LOF),DBSCAN;

多维数据建议:孤立森林(Isolation Forest),一类支持向量机(One-Class SVM),主成分分析(PCA),高斯混合模型(GMM)。

【异常值处理】

【删除异常值数据】

直接删除检测到的异常值。优点:简单直接,能有效去除异常值。缺点:可能丢失重要信息,尤其在数据量较小的情况下。

def remove_outliers(X, outliers):
    return np.delete(X, outliers, axis=0)


X_normal_no_outliers = remove_outliers(X_normal_with_outliers, outliers_gmm_normal)
X_uniform_no_outliers = remove_outliers(X_uniform_with_outliers, outliers_gmm_uniform)


plot_data(X_normal_no_outliers, [], 'Removed Outliers - Normal')
plot_data(X_uniform_no_outliers, [], 'Removed Outliers - Uniform')

【均值/中位数替换】

将异常值替换为数据的均值或中位数。优点:能保持数据规模,对大多数情况适用。缺点:可能掩盖数据的真实波动。

def replace_with_mean(X, outliers):
    mean = np.mean(X, axis=0)
    X[outliers] = mean
    return X


X_normal_mean_replaced = replace_with_mean(X_normal_with_outliers.copy(), outliers_std_normal)
X_uniform_mean_replaced = replace_with_mean(X_uniform_with_outliers.copy(), outliers_std_uniform)

【前/后值替换】

在时间序列数据中,使用前一个或后一个值替换异常值。优点:简单直接,适用于时间序列数据。缺点:可能引入滞后效应,影响数据的真实性。

def replace_with_previous(X, outliers):
    for outlier in outliers[0]:
        if outlier == 0:
            X[outlier] = X[outlier + 1]
        else:
            X[outlier] = X[outlier - 1]
    return X


X_normal_prev_replaced = replace_with_previous(X_normal_with_outliers.copy(), outliers_std_normal)
X_uniform_prev_replaced = replace_with_previous(X_uniform_with_outliers.copy(), outliers_std_uniform)

【插值法】

利用线性插值或其他插值方法替换异常值。优点:能保持数据的连续性和趋势。缺点:对插值方法的选择较为敏感。

def interpolate_outliers(X, outliers):
    for outlier in outliers[0]:
        if outlier == 0:
            X[outlier] = X[outlier + 1]
        elif outlier == len(X) - 1:
            X[outlier] = X[outlier - 1]
        else:
            X[outlier] = (X[outlier - 1] + X[outlier + 1]) / 2
    return X


X_normal_interpolated = interpolate_outliers(X_normal_with_outliers.copy(), outliers_std_normal)
X_uniform_interpolated = interpolate_outliers(X_uniform_with_outliers.copy(), outliers_std_uniform)

【对数变换】

对数据进行对数变换,可以减小异常值的影响。优点:适用于具有指数分布的数据。缺点:不能处理负值和零值,适用范围有限。

def log_transform(X):
    return np.log1p(X)  # log1p能处理X中的0值


X_normal_log_transformed = log_transform(X_normal_with_outliers)
X_uniform_log_transformed = log_transform(X_uniform_with_outliers)

【平方根变换】

通过平方根变换减少异常值的影响。优点:适用于具有正偏态分布的数据。缺点:对负值和零值不适用。

def sqrt_transform(X):
    return np.sqrt(X)


X_normal_sqrt_transformed = sqrt_transform(X_normal_with_outliers)
X_uniform_sqrt_transformed = sqrt_transform(X_uniform_with_outliers)

【标准化】

将数据缩放到一个标准正态分布。优点:消除量纲影响,适用于多种分析方法。缺点:对非正态分布的数据效果一般。

def standardize(X):
    return (X - np.mean(X, axis=0)) / np.std(X, axis=0)


X_normal_standardized = standardize(X_normal_with_outliers)
X_uniform_standardized = standardize(X_uniform_with_outliers)

【归一化】

将数据缩放到[0, 1]的范围内。优点:适用于范围差异较大的数据。缺点:对异常值敏感,可能被极端值影响。

def normalize(X):
    min_val = np.min(X, axis=0)
    max_val = np.max(X, axis=0)
    return (X - min_val) / (max_val - min_val)


X_normal_normalized = normalize(X_normal_with_outliers)
X_uniform_normalized = normalize(X_uniform_with_outliers)

【鲁棒统计量】

使用中位数和四分位数等对异常值不敏感的统计量。优点:对异常值不敏感,适用于非正态分布的数据。缺点:不能完全消除异常值的影响。

def robust_standardize(X):
    median = np.median(X, axis=0)
    IQR = np.percentile(X, 75, axis=0) - np.percentile(X, 25, axis=0)
    return (X - median) / IQR


X_normal_robust_standardized = robust_standardize(X_normal_with_outliers)
X_uniform_robust_standardized = robust_standardize(X_uniform_with_outliers)

通过这些示例,我们可以看到各种异常值处理方法在处理数据异常值时的效果。不同的方法适用于不同类型的数据和场景,选择合适的方法可以有效提高数据分析的准确性和可靠性。

链接是我使用PowerBI整合的历史文章,按类型分类,可以根据需求查询:Microsoft Power BI↓

https://app.powerbi.com/view?r=eyJrIjoiNjI2NWQ3NjktYjU0ZC00ZWZhLTgzMDgtMGI4ZTk1ZDlkODM3IiwidCI6IjI3NDQ3MWQ0LTM4ZDQtNDVlZS1hMmJkLWU1NTVhOTBkYzM4NiJ9

End

最近发表
标签列表