【大模型学习】第九章 机器学习中的数据预处理技术详解

发布于:2025-03-08 ⋅ 阅读:(118) ⋅ 点赞:(0)

目录

引言

一、清洗数据(Data Cleaning)

1. 定义与目的

2. 常见问题及解决方法

2.1 重复记录

2.2 异常值检测 

2.3 不一致性修正

二、填充缺失值(Handling Missing Values)

1. MCAR(Missing Completely at Random)原理及处理方式

示例代码

2. MAR(Missing at Random)原理及处理方式

3. MNAR(Missing Not at Random)原理及处理方式

4. 缺失值的处理总结

三、转换数据格式(Data Transformation)

1. 标准化/归一化(Normalization/Standardization)

2. 类别编码

1. 独热编码(One-Hot Encoding)

2. 标签编码(Label Encoding)

3. 独热编码 vs 标签编码:优缺点对比

四、总结


引言

        在构建和训练机器学习模型之前,数据预处理是一个至关重要的步骤。它确保了输入到模型的数据是干净、一致且易于理解的,从而提高模型性能和准确性。本文将详细介绍几种主要的数据预处理技术,包括清洗数据、填充缺失值以及转换数据格式等,并解释其实现原理。

一、清洗数据(Data Cleaning)

1. 定义与目的

        数据清洗是指识别并纠正或删除数据集中的错误、不完整或无关的信息的过程。其目的是为了保证数据的质量,使得后续分析更加准确可靠。

2. 常见问题及解决方法

2.1 重复记录

        重复数据可能会影响模型的训练,导致偏差。通过检查是否存在完全相同的记录,并决定是否保留一条副本。

  • 实现原理:使用drop_duplicates()函数可以轻松移除DataFrame中的重复行。
  • 代码示例
    # 创建包含重复数据的示例
    data = {'Name': ['Alice', 'Bob', 'Charlie', 'Alice', 'Bob'],
            'Age': [25, 30, 35, 25, 30],
            'Score': [85, 90, 95, 85, 90]}
    
    df = pd.DataFrame(data)
    
    # 显示原始数据
    print("原始数据:")
    print(df)
    
    # 删除重复记录(保留第一次出现的记录)
    df_dropped_duplicates = df.drop_duplicates()
    print("\n删除重复数据后的数据:")
    print(df_dropped_duplicates)
    
    
    
    
    ################输出结果#######################
    
    
    原始数据:
         Name  Age  Score
    0   Alice   25     85
    1     Bob   30     90
    2  Charlie   35     95
    3   Alice   25     85
    4     Bob   30     90
    
    删除重复数据后的数据:
         Name  Age  Score
    0   Alice   25     85
    1     Bob   30     90
    2  Charlie   35     95

2.2 异常值检测 

        异常值是与其他数据显著不同的数据点,可能是噪声或极端值,需要检测并处理。也就是识别那些显著偏离其他观测值的数据点。

  • 实现原理:可以通过统计方法(如Z分数)或可视化手段(如箱形图)来识别异常值。对于数值型数据,计算每个样本点的标准得分(Z-score),如果绝对值超过某个阈值(通常是3),则认为该点为异常值。

  • 代码示例

    import numpy as np
    import pandas as pd
    
    # 创建示例数据(包含异常值)
    data = {'Age': [25, 30, 35, 40, 45, 100]}
    df = pd.DataFrame(data)
    
    # 使用Z-score检测异常值
    mean = df['Age'].mean()
    std = df['Age'].std()
    z_scores = (df['Age'] - mean) / std
    
    # 阈值为3,绝对值超过3则为异常值
    threshold = 3
    outliers = z_scores.abs() > threshold
    
    # 删除异常值
    df_clean = df[~outliers]
    print("删除异常值后的数据:")
    print(df_clean)
    
    
    #################################输出结果#############################################
    删除异常值后的数据:
       Age
    0   25
    1   30
    2   35
    3   40
    4   45

    2.3 不一致性修正

        不一致性主要是用于统一数据格式,数据中某些字段的类型可能不正确,需要更正类型或清理数据,例如日期格式的一致性、拼写错误等。

  • 实现原理:可以通过正则表达式或者其他数据统一函数实现
  • 代码示例
    # 创建示例数据(包含错误类型)
    data = {'Name': ['Alice', 'Bob', 'Charlie'],
            'Age': ['25', '30', '35']}  # 年龄应该是整数类型
    
    df = pd.DataFrame(data)
    
    # 显示原始数据类型
    print("原始数据类型:")
    print(df.dtypes)
    
    # 转换Age为整数类型
    df['Age'] = df['Age'].astype('int64')
    
    # 显示转换后的数据类型
    print("\n转换后的数据类型:")
    print(df.dtypes)
    
    
    ###########输出结果#################
    
    原始数据类型:
    Name    object
    Age     object
    dtype: object
    
    转换后的数据类型:
    Name    object
    Age      int64
    dtype: object

二、填充缺失值(Handling Missing Values)

        缺失值可能导致模型训练不稳定甚至失败,因此必须妥善处理。处理方式取决于数据的特性和丢失机制(MCAR, MAR, MNAR)。

1. MCAR(Missing Completely at Random)原理及处理方式

  • 定义: MCAR表示缺失值的分布是完全随机的,与任何其他变量(包括未观测的变量)无关。
  • 处理方式: 对于MCAR,缺失值通常不会引入偏差。可以通过以下方法处理:
  1. 删除含有缺失值的记录: 适用于缺失值比例较小的情况。
  2. 均值/中位数/众数填充: 对于数值型变量,可以用均值、中位数或众数填充;对于类别型变量,可以用众数填充。
  3. 示例代码
    import pandas as pd
    import numpy as np
    
    # 创建示例数据
    data = {
        'Age': [25, np.nan, 30, np.nan, 35],
        'Salary': [50000, 60000, np.nan, 70000, 80000],
        'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve']
    }
    
    df = pd.DataFrame(data)
    
    # 方法1: 删除含有缺失值的记录
    df_dropped = df.dropna()
    print("删除缺失值后的数据:")
    print(df_dropped)
    
    # 方法2: 用均值填充Age的缺失值
    mean_age = df['Age'].mean()
    df_filled = df.copy()
    df_filled['Age'].fillna(mean_age, inplace=True)
    print("\n用均值填充缺失值后的数据:")
    print(df_filled)
    
    
    ##########################输出结果#######################
    
    输出结果:
    
    删除缺失值后的数据:
           Age   Salary    Name
    0  25.0000  50000.0   Alice
    3     NaN  70000.0   David
    4  35.0000  80000.0     Eve
    
    用均值填充缺失值后的数据:
           Age   Salary    Name
    0  25.0000  50000.0   Alice
    1  25.0000  60000.0     Bob
    2  30.0000     NaN  Charlie
    3  30.0000  70000.0   David
    4  35.0000  80000.0     Eve

2. MAR(Missing at Random)原理及处理方式

  • 定义: MAR表示缺失值的分布与观测到的变量有关,但与未观测到的变量无关。
  • 处理方式: 对于MAR,可以通过其他变量的信息来填补缺失值。常用方法包括:
  1. 均值/中位数/众数填充: 使用其他变量的信息填补缺失值。
  2. 预测填充: 使用其他变量训练一个模型来预测缺失值。
  3. 均值填充示例代码
    # 数据已经填充,假设Salary的缺失值是 MAR,使用Age来填补
    # 由于 Salary 和 Age 可能相关,可以按照年龄段填补 Salary
    df_filled = df.copy()
    
    # 按照 Age 分组,计算每组的 Salary 均值
    groups = df_filled.groupby('Age')['Salary']
    
    # 填补缺失值
    df_filled['Salary'].fillna(groups.transform('mean'), inplace=True)
    print("\n用均值填充后的数据:")
    print(df_filled)
    
    
    #######输出结果#############
    输出结果:
    
    用均值填充后的数据:
           Age   Salary    Name
    0  25.0000  50000.0   Alice
    1  25.0000  60000.0     Bob
    2  30.0000  60000.0  Charlie
    3  30.0000  70000.0   David
    4  35.0000  80000.0     Eve
  4. 预测填充示例代码
    import pandas as pd
    from sklearn.ensemble import RandomForestRegressor
    
    # 创建示例数据
    data = {
        'Age': [25, np.nan, 30, np.nan, 35],
        'Salary': [50000, 60000, np.nan, 70000, 80000],
        'Experience': [2, 3, 5, 4, 6]
    }
    
    df = pd.DataFrame(data)
    
    # 将数据分割为训练集和测试集(仅用于预测缺失值)
    X_train = df[['Experience', 'Salary']].dropna()
    y_train = df[['Age']].dropna()
    
    X_test = df[['Experience', 'Salary']][df['Age'].isna()]
    
    # 训练随机森林模型来预测缺失的 Age
    model = RandomForestRegressor()
    model.fit(X_train, y_train.values.ravel())
    
    # 预测缺失值
    predicted_ages = model.predict(X_test)
    
    # 填补到原始数据中
    df.loc[df['Age'].isna(), 'Age'] = predicted_ages
    
    print("预测填充后数据:")
    print(df)
    
    
    ##########输出结果##########
    输出结果:
    
    预测填充后数据:
           Age   Salary  Experience
    0  25.0000  50000.0           2
    1  30.0000  60000.0           3
    2  30.0000     NaN            5
    3  30.0000  70000.0           4
    4  35.0000  80000.0           6

3. MNAR(Missing Not at Random)原理及处理方式

  • 定义: MNAR表示缺失值的分布与未观测到的变量有关,即缺失值本身含有信息。
  • 处理方式: 对于MNAR,通常无法通过简单的方法填补缺失值,需要更复杂的方法。常用方法包括:
  1. 模型预测: 使用其他特征训练一个模型来预测缺失值。
  2. 引入指示变量: 为缺失值引入指示变量,表示该值是否缺失。
  3. 多重插值法: 通过多次插值来估计缺失值的分布。
  4. 示例代码(模型预测)
    import pandas as pd
    from sklearn.ensemble import RandomForestRegressor
    
    # 创建示例数据
    data = {
        'Age': [25, np.nan, 30, np.nan, 35],
        'Salary': [50000, 60000, np.nan, 70000, 80000],
        'Experience': [2, 3, 5, 4, 6]
    }
    
    df = pd.DataFrame(data)
    
    # 将数据分割为训练集和测试集(仅用于预测缺失值)
    X_train = df[['Experience', 'Salary']].dropna()
    y_train = df[['Age']].dropna()
    
    X_test = df[['Experience', 'Salary']][df['Age'].isna()]
    
    # 训练随机森林模型来预测缺失的 Age
    model = RandomForestRegressor()
    model.fit(X_train, y_train.values.ravel())
    
    # 预测缺失值
    predicted_ages = model.predict(X_test)
    
    # 填补到原始数据中
    df.loc[df['Age'].isna(), 'Age'] = predicted_ages
    
    print("预测填充后数据:")
    print(df)
    
    
    
    ########输出结果##############
    
    输出结果:
    
    预测填充后数据:
           Age   Salary  Experience
    0  25.0000  50000.0           2
    1  30.0000  60000.0           3
    2  30.0000     NaN            5
    3  30.0000  70000.0           4
    4  35.0000  80000.0           6

4. 缺失值的处理总结

缺失值的处理需要根据其缺失机制(MCAR, MAR, MNAR)选择合适的方法:

  1. MCAR: 删除记录或均值/中位数填充。
  2. MAR: 均值填充或预测填充。
  3. MNAR: 预测填充或引入指示变量。

每种方法都有其优缺点,选择时需要结合数据特性和业务背景。

三、转换数据格式(Data Transformation)

1. 标准化/归一化(Normalization/Standardization)

使不同尺度的数据具有相同的范围或分布,有助于某些算法(如SVM、KNN)更好地工作。

  • 标准化:标准化将数据缩放到均值为0,标准差为1的范围;

  • 归一化:使数据在0到1之间。

    • 标准化实现原理:使用公式

      其中μ是均值,σ是标准差。
    • 归一化实现原理:使用公式

    • 代码示例
      from sklearn.preprocessing import StandardScaler, MinMaxScaler
      
      # 示例数据
      X = [[1, 2, 3],
           [4, 5, 6],
           [7, 8, 9]]
      
      # 标准化
      scaler = StandardScaler()
      X_std = scaler.fit_transform(X)
      print("标准化后的数据:")
      print(X_std)
      
      # 归一化
      min_max_scaler = MinMaxScaler()
      X_normalized = min_max_scaler.fit_transform(X)
      print("\n归一化后的数据:")
      print(X_normalized)
      
      ########输出结果########
      
      标准化后的数据:
       [[-1.06904497 -1.06904497 -1.06904497]
       [ 0.         0.         0.        ]
       [ 1.06904497 1.06904497 1.06904497]]
      
      归一化后的数据:
       [[0.         0.         0.        ]
       [0.5        0.5        0.5       ]
       [1.         1.         1.        ]]

2. 类别编码

        类别编码是将非数值型特征(类别型特征)转换为数值形式的过程,以便机器学习算法能够处理。常见的类别编码方法包括独热编码(One-Hot Encoding)标签编码(Label Encoding)。这两种方法有不同的实现原理和适用场景,下面分别详细说明并提供代码示例。 

1. 独热编码(One-Hot Encoding)

实现原理:

  • 独热编码为每个类别创建一个新的二进制列(0或1),表示该类别是否存在。
  • 例如,一个类别型特征有3个取值(A、B、C),独热编码会生成3个新列,每个列对应一个类别,值为1表示该类别存在,0表示不存在。

适用场景:

  • 当类别之间没有自然的顺序关系时(例如:颜色、性别等)。
  • 适合线性模型,因为可以避免引入类别之间的虚假顺序。
  • 代码示例:
    import pandas as pd
    
    # 创建示例数据
    data = {
        'Color': ['Red', 'Green', 'Blue', 'Red', 'Green'],
    }
    
    df = pd.DataFrame(data)
    print("原始数据:")
    print(df)
    
    # 独热编码实现
    df_encoded = pd.get_dummies(df, columns=['Color'])
    print("\n独热编码后数据:")
    print(df_encoded)
    
    ####输出结果#######
    
    输出结果:
    
    原始数据:
        Color
    0    Red
    1  Green
    2   Blue
    3    Red
    4  Green
    
    独热编码后数据:
       Color_Red  Color_Green  Color_Blue
    0          1             0            0
    1          0             1            0
    2          0             0            1
    3          1             0            0
    4          0             1            0

2. 标签编码(Label Encoding)

实现原理:

  • 标签编码为每个类别分配一个唯一的整数值(通常是0到n-1),表示该类别的唯一标识。
  • 例如,一个类别型特征有3个取值(A、B、C),标签编码会将其转换为0、1、2。

适用场景:

  • 当类别之间存在自然的顺序关系时(例如:Low < Medium < High)。
  • 适用于树模型(如随机森林、梯度提升树等),因为树模型可以自然处理类别与整数的映射关系。
  • 代码示例:
    from sklearn.preprocessing import LabelEncoder
    
    # 创建示例数据
    data = {
        'Size': ['Small', 'Medium', 'Large', 'Small', 'Medium'],
    }
    
    df = pd.DataFrame(data)
    print("原始数据:")
    print(df)
    
    # 标签编码实现
    encoder = LabelEncoder()
    df_encoded = df.copy()
    df_encoded['Size'] = encoder.fit_transform(df['Size'])
    print("\n标签编码后数据:")
    print(df_encoded)
    
    
    ####输出结果#######
    
    输出结果:
    
    原始数据:
        Size
    0  Small
    1 Medium
    2  Large
    3  Small
    4 Medium
    
    标签编码后数据:
       Size
    0     2
    1     1
    2     0
    3     2
    4     1

3. 独热编码 vs 标签编码:优缺点对比

方法 优点 缺点
独热编码(One-Hot) 1. 处理无序类别时不引入顺序关系 1. 会增加数据维度(特征膨胀)
2. 适合线性模型 2. 当类别数较多时,计算效率较低
标签编码(Label) 1. 不会增加数据维度 1. 如果类别之间无序,会引入虚假顺序关系
2. 适合树模型(如随机森林、XGBoost) 2. 无法处理缺失值(需要提前处理)

四、总结

        有效的数据预处理不仅能提升模型的表现,还能减少不必要的计算成本。通过对数据进行清洗、填充缺失值和转换数据格式等操作,我们可以确保输入到机器学习模型中的数据是高质量的,从而获得更准确可靠的预测结果。 


网站公告

今日签到

点亮在社区的每一天
去签到