机器学习中异常值的处理技术总结

文摘   2024-10-15 00:02   中国  

1 引言

在数据分析中,异常值是指那些显著偏离其他数据点的值,它们可能比其他数据高得多或低得多。以一个教室里的学生考试成绩为例,如果大多数学生的成绩在50到80分之间,而有一名同学得了5分,另一名同学得了100分,那么这两个极端的分数就是异常值(outliers)的典型例子。

异常值在现实世界的数据集中非常普遍,而如何处理这些异常值将显著影响分析结果。因此,本文将介绍一些处理异常值的基本技术,并通过简单的示例和编码演示来帮助您快速上手。

2 什么是异常值?

在深入探讨处理技术之前,我们先来明确异常值的定义。异常值是指在数据集中显著偏离其他观测值的数值。例如,在一个大多数学生年龄在18到22岁之间的班级中,如果有一位50岁的学生,那么他的年龄就是一个异常值。

2.1 为什么要处理异常值?

异常值可能会对分析结果产生扭曲效应,导致分析不准确,甚至得出错误的结论。例如,如果您试图计算某个社区的平均收入,但该社区居住着一位亿万富翁,那么这位富翁的收入可能会显著提高平均收入,从而误导您对社区财富状况的判断。

为了确保数据分析的准确性和可靠性,识别和处理异常值是数据预处理中的一个重要步骤。接下来,我们将探讨一些常用的方法来识别和处理这些异常值。

3 处理离群值的常用技术

接下来,我们将探讨一些简单而有效的技术来处理异常值。为了更好地理解这些技术,我们还将提供一个编码演示,展示如何应用每种方法。

3.1 Z分数法

作用:Z分数(Z-Score)法是一种衡量数据点与平均值之间距离的方法,它通过计算数据点与平均值的标准差数量来实现。如果某个值与平均值相差超过3个标准差,则通常被视为异常值。Z 分数表对于快速查找和比较Z分数非常有用。

何时使用:当您的数据呈正态分布时(即钟形曲线),Z 分数法特别有效。

示例

假设我们有100个人的身高数据,大多数人的身高在150厘米到180厘米之间,但如果有一个人的身高是250厘米,那么这个数据点就是一个异常值。

import pandas as pdimport numpy as np
# 生成样本数据:人们的身高(单位:厘米)data = pd.DataFrame({'Height': np.random.normal(170, 10, 100)})
# 添加一个异常值data.loc[0, 'Height'] = 250 # 这是我们要识别的异常值
# 计算Z分数data['Z_score'] = (data['Height'] - data['Height'].mean()) / data['Height'].std()
# 识别异常值(Z分数大于3或小于-3outliers = data[np.abs(data['Z_score']) > 3]
print("异常值:")print(outliers)

3.2 IQR 法(四分位距法)

作用:IQR 方法通过计算数据中间50%的分布范围来识别异常值。这种方法通过找出明显超出这个范围的值来帮助识别异常值。

运作方式

  1. 计算第一个四分位数(Q1):这是数据的第25个百分位数。

  2. 计算第三个四分位数(Q3):这是数据的第75个百分位数。

  3. 计算IQR(四分位距):用Q3减去Q1得到IQR。

    [ \text{IQR} = Q3 - Q1 ]

  1. 确定异常值边界

  • 下限:( Q1 - 1.5 \times \text{IQR} )

  • 上限:( Q3 + 1.5 \times \text{IQR} )

  • 识别异常值:任何低于下限或高于上限的数据点都被视为异常值。

  • 示例:在一项关于人们每月支出的调查中,如果大多数人的支出在500美元到1500美元之间,但少数人的支出超过4000美元,那么这些高支出就是异常值。

    import pandas as pdimport numpy as np
    # 样本数据:每月支出data = { 'Monthly Expenses': [500, 600, 700, 800, 1500, 1600, 2000, 4000, 4500, 5000]}
    # 创建DataFramedf = pd.DataFrame(data)
    # 计算Q1和Q3Q1 = df['Monthly Expenses'].quantile(0.25)Q3 = df['Monthly Expenses'].quantile(0.75)IQR = Q3 - Q1
    # 计算异常值边界lower_bound = Q1 - 1.5 * IQRupper_bound = Q3 + 1.5 * IQR
    # 识别异常值outliers = df[(df['Monthly Expenses'] < lower_bound) | (df['Monthly Expenses'] > upper_bound)]
    print("使用IQR方法识别的异常值:")print(outliers)

    3.3 修改后的Z分数法

    作用:修改后的Z分数(Modified Z-Score)法是一种对异常值更加稳健的检测方法。与传统的 Z 分数法不同,它使用中位数和中位数绝对偏差(MAD)来衡量数据点与中位数的距离,从而减少了异常值对计算结果的影响。

    运作方式

    1. 计算中位数:找出数据集的中位数。

    2. 计算绝对偏差:计算每个数据点与中位数的绝对偏差。

    3. 计算MAD(中位数绝对偏差):找出这些绝对偏差的中位数。

    4. 计算修改后的 Z 分数:使用以下公式计算修改后的 Z 分数,以识别异常值。

      [ \text{Modified Z} = 0.6745 \times \frac{\text{X} - \text{中位数}}{\text{MAD}} ]

    其中:

    • X:代表您正在评估的特定数据点。

    • 中位数:是数据集排序后的中间值。

    • MAD(中位数绝对偏差):是衡量数据集中的值偏离中位数的程度的指标。

    • 0.6745:是一个比例因子,用于使修改后的 Z 分数与标准正态分布相匹配。

    1. 识别异常值:通常,如果修改后的 Z 分数的绝对值大于3,则认为该数据点是异常值。

    示例:在记录一组人的日常步数时,如果大多数人的步行步数在2000到10000步之间,但少数人的步数达到30000步,那么这些非常高的步数可能就是异常值。

    import pandas as pdimport numpy as np
    # 样本数据:每日步数steps_data = { 'Daily Steps': [2000, 3000, 5000, 7000, 9000, 10000, 15000, 30000]}
    # 创建DataFramedf_steps = pd.DataFrame(steps_data)
    # 计算中位数和MADmedian = df_steps['Daily Steps'].median()mad = np.median(np.abs(df_steps['Daily Steps'] - median))
    # 计算修改后的Z分数df_steps['Modified Z'] = 0.6745 * (df_steps['Daily Steps'] - median) / mad
    # 识别异常值outliers_modified = df_steps[np.abs(df_steps['Modified Z']) > 3]
    print("\n使用修改后的Z分数法识别的异常值:")print(outliers_modified)

    3.4 箱形图可视化

    功能:箱形图是一种非常直观的数据可视化工具,它通过展示数据的分布情况来帮助我们轻松识别异常值。箱形图的箱体表示数据的四分位距(IQR),而“须线”(即从箱体延伸出的线)标示了数据的正常范围。任何超出须线的点都被视为潜在的异常值。

    示例:在分析篮球运动员的身高数据时,我们可能会发现大多数球员的身高集中在180厘米到210厘米之间,但少数球员的身高超过230厘米,这些极端值在箱形图中会非常明显。

    import matplotlib.pyplot as plt
    # 样本数据:篮球运动员的身高(单位:厘米)heights = [180, 185, 190, 195, 200, 210, 220, 230, 250]
    # 创建箱形图plt.boxplot(heights)plt.title('篮球运动员身高的箱形图')plt.ylabel('身高 (cm)')plt.show()

    3.5 Winsorization(温莎化)

    功能:Winsorization是一种减少异常值影响的技术,它通过将极端值替换为数据集中的某个特定百分位数的值来实现,而不是完全删除这些异常值。例如,您可以将极高的值替换为下一个最高的非异常值,这样可以在不丢失数据的情况下减少异常值的影响。

    示例:在房价数据集中,如果大多数房屋的价格在150,000到300,000美元之间,但有一套房屋的挂牌价格异常地高达10,000,000美元,那么可以将这个异常的高价替换为最高的非异常值价格,例如95百分位数的价格,以保持数据的真实性和实用性。

    import pandas as pdimport numpy as np
    # Winsorization示例data_prices = { 'Home Prices': [150000, 200000, 250000, 300000, 10000000] # 一个极端的异常值}
    # 创建DataFramedf_prices = pd.DataFrame(data_prices)
    # Winsorization:将异常值限制在95百分位数cap = df_prices['Home Prices'].quantile(0.95)df_prices['Capped Prices'] = np.where(df_prices['Home Prices'] > cap, cap, df_prices['Home Prices'])
    print("\n温莎化处理后的数据:")print(df_prices)

    在上述代码中,我们首先计算了房价数据的95百分位数,然后将所有超过这个百分位数的价格替换为这个百分位数的值。这样,极端的异常值就被“温挈化”了,从而减少了它们对数据分析的影响。这种方法特别适用于不希望完全删除异常值,但又希望减少它们影响的情况。

    3.6 对数转换

    功能:对数转换是一种通过应用对数函数来减少数据中极端值影响的技术。这种方法特别适用于处理正偏态分布的数据,因为它可以有效地压缩数据的尺度,使得数据更加接近正态分布。

    示例:在分析收入数据时,我们经常会遇到一些非常高的收入值,这些值可能会扭曲数据的整体分布。通过对数据进行对数转换,我们可以将这些高收入值的影响降低,从而使得数据更加规范化,更易于进行进一步的分析。

    import pandas as pdimport numpy as np
    # 样本收入数据income_data = { 'Annual Income': [20000, 30000, 50000, 80000, 200000, 1000000] # 包含一个较大的异常值}
    # 创建DataFramedf_income = pd.DataFrame(income_data)
    # 应用对数转换df_income['Log Income'] = np.log(df_income['Annual Income'])
    print("\n对数转换后的数据:")print(df_income)

    4 结论

    异常值是数据集中不可避免的一部分,它们的存在可能会显著影响数据分析的结果。因此,如何妥善处理这些异常值对于确保分析的准确性和可靠性至关重要。通过运用Z分数、IQR、修改后的Z分数、箱形图、Winsorization以及对数转换等技术,我们可以有效地管理和减少异常值的影响,从而提高分析结果的准确性。

    4.1 技巧

    • 数据可视化:在处理异常值之前和之后,始终对数据进行可视化,这有助于您直观地了解异常值对数据分布的影响。

    • 考虑数据上下文:在决定如何处理异常值时,要考虑数据的具体情况和分析的上下文。有时,异常值可能代表了重要的、值得进一步分析的现象,因此在某些情况下,保留这些异常值可能是有意义的。


    架构师之道
    研究企业架构,研究企业数字化转型,跟踪和探索云计算、大数据、工业互联网、物联网、区块链等领域的最新动向和技术分享,帮助架构师进阶首席科学家!
     最新文章