当前位置: 首页 > article >正文

1.数据清洗与预处理——Python数据挖掘(数据抽样、数据分割、异常值处理、缺失值处理)

在数据挖掘与机器学习项目中,数据清洗与预处理是确保模型效果的关键步骤。本文将以实践为导向,介绍数据抽样、数据分割、异常值处理以及缺失值处理的原理、策略和实现代码,帮助您构建一个完善的数据预处理流程。

文章目录

  • 一、 数据抽样
    • 1.1 抽样方法简介
      • 示例代码:抽样演示
  • 二、 数据分割
    • 2.1 训练集、验证集与测试集
    • 2.2 分割方法与注意事项
      • 示例代码:数据分割
  • 三、 异常值处理
    • 3.1 异常值检测
      • 示例代码:异常值检测与处理
  • 四、 缺失值处理
    • 4.1 缺失值检测与统计
      • 示例代码:检测缺失值
    • 4.2 缺失值填充策略
      • 示例代码 1:使用 Pandas 的 fillna() 填充缺失值
      • 示例代码 2:使用 scikit-learn 的 SimpleImputer 进行填充
  • 总结


一、 数据抽样

1.1 抽样方法简介

  • 随机抽样:直接从数据中随机选择一定比例的样本,适用于数据总体分布均匀的情况。
  • 分层抽样:根据某个或多个特征先将数据划分为不同“层”,再在各层中随机抽样,这样可以确保各类别(或层)的比例在样本中得到充分体现,避免抽样偏差。

提示: 抽样偏差指的是样本未能真实反映总体情况,从而导致后续模型效果降低。保证抽样的代表性是提高模型泛化能力的重要前提。

示例代码:抽样演示

import pandas as pd
import numpy as np

# 构造一个示例 DataFrame,其中 'target' 表示类别
data = {
    'feature1': np.arange(1, 21),
    'feature2': np.random.randint(1, 100, 20),
    'target':   [0]*10 + [1]*10  # 假设前10个样本属于类别0,后10个样本属于类别1
}
df = pd.DataFrame(data)
print("原始数据:")
print(df.head())

# 随机抽样:从 DataFrame 中随机抽取 50% 的样本
random_sample = df.sample(frac=0.5, random_state=42)
print("\n随机抽样结果:")
print(random_sample)

# 分层抽样:确保类别0和类别1的比例一致
# 使用 Pandas 的 groupby 与 sample 进行简单的分层抽样
stratified_sample = df.groupby('target', group_keys=False).apply(lambda x: x.sample(frac=0.5, random_state=42))
print("\n分层抽样结果:")
print(stratified_sample)

二、 数据分割

为了构建并评估模型,我们通常将数据集划分为训练集、验证集和测试集。

2.1 训练集、验证集与测试集

  • 训练集:用于模型参数的学习。
  • 验证集:用于调参和模型选择,防止模型过拟合。
  • 测试集:用于评估模型在未知数据上的最终表现。

2.2 分割方法与注意事项

常用的方法有“留出法”和“交叉验证”。本文采用留出法,并使用 scikit-learn 中的 train_test_split 函数实现,同时通过 stratify 参数实现分层分割,保证各类别比例一致。

示例代码:数据分割

from sklearn.model_selection import train_test_split

# 以前面构造的 DataFrame df 为例,其中 'target' 为分层依据
# 首先将数据划分为训练集(60%)和临时集(40%)
train_df, temp_df = train_test_split(df, test_size=0.4, random_state=42, stratify=df['target'])
# 再将临时集均分为验证集和测试集(各占20%)
val_df, test_df = train_test_split(temp_df, test_size=0.5, random_state=42, stratify=temp_df['target'])

print("\n训练集样本数:", len(train_df))
print("验证集样本数:", len(val_df))
print("测试集样本数:", len(test_df))

print("\n训练集类别分布:")
print(train_df['target'].value_counts())
print("验证集类别分布:")
print(val_df['target'].value_counts())
print("测试集类别分布:")
print(test_df['target'].value_counts())

三、 异常值处理

异常值是指那些与大多数数据差异较大的值,可能由数据采集错误或真实的极端情况引起。常用的检测方法有 Z-score 和 IQR(四分位距)方法。此处我们采用 IQR 方法进行演示。

3.1 异常值检测

  • IQR 方法
    1. 计算数据的第一四分位数(Q1)和第三四分位数(Q3)。
    2. 计算 IQR = Q3 - Q1。
    3. 定义异常值边界:低于 Q1 - 1.5IQR 或高于 Q3 + 1.5IQR 的数据被视为异常值。

示例代码:异常值检测与处理

# 构造一个包含异常值的示例数据集
df_outlier = pd.DataFrame({
    'feature': [10, 12, 12, 13, 12, 14, 100]  # 此处 100 为明显异常值
})
print("\n原始数据:")
print(df_outlier)

# 计算 Q1、Q3 与 IQR
Q1 = df_outlier['feature'].quantile(0.25)
Q3 = df_outlier['feature'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 标记异常值
df_outlier['is_outlier'] = ((df_outlier['feature'] < lower_bound) | (df_outlier['feature'] > upper_bound))
print("\n异常值检测结果:")
print(df_outlier)

# 处理策略:删除异常值
df_clean = df_outlier[~df_outlier['is_outlier']].drop(columns=['is_outlier'])
print("\n删除异常值后的数据:")
print(df_clean)

补充说明:
除了删除异常值外,另一种方法是对异常值进行修正或用临近值插补,具体策略需根据业务需求决定。


四、 缺失值处理

缺失值问题在实际数据中非常常见。缺失值处理主要包括检测、统计和填充。合理的填充方法可以避免因数据不完整导致的信息损失和偏差。

4.1 缺失值检测与统计

使用 Pandas 的 isnull()notnull()info() 方法,可以快速识别数据中的缺失值情况。

示例代码:检测缺失值

# 构造包含缺失值的示例数据集
df_missing = pd.DataFrame({
    'feature1': [1, 2, np.nan, 4, 5],
    'feature2': [np.nan, 3, 6, 2, 7],
    'target':   [0, 1, 0, 1, 0]
})

print("\n数据概览:")
print(df_missing.info())

print("\n缺失值统计:")
print(df_missing.isnull().sum())

4.2 缺失值填充策略

在数据预处理中,处理缺失值是一个不可忽视的环节。缺失值如果不加处理可能会影响模型的稳定性和预测准确性。常见的填充方法包括:

  • 均值填充:适用于数值型数据,当数据分布较为对称时,用均值替换缺失值可以减少偏差。
  • 中位数填充:当数据中存在异常值时,中位数比均值更加稳健,可以减少异常值对填充值的影响。
  • 众数填充:适用于分类变量,对于文本或离散数据,用出现频率最高的值进行填充。
  • 插值法:基于数据趋势进行线性或多项式插值,常用于时间序列数据,可以通过前后趋势预测缺失值。

下面通过具体代码示例来展示这些填充策略。


示例代码 1:使用 Pandas 的 fillna() 填充缺失值

import pandas as pd
import numpy as np

# 构造包含缺失值的示例数据集
df_missing = pd.DataFrame({
    'feature1': [1, 2, np.nan, 4, 5],
    'feature2': [np.nan, 3, 6, 2, 7],
    'category': ['A', 'B', np.nan, 'B', 'A']
})

print("原始数据:")
print(df_missing)

# 策略一:直接删除包含缺失值的记录(谨慎使用,可能导致信息丢失)
df_dropna = df_missing.dropna()
print("\n删除缺失值后的数据:")
print(df_dropna)

# 策略二:使用均值填充(适用于数值型变量,数据分布较为对称时)
df_fill_mean = df_missing.copy()
df_fill_mean['feature1'].fillna(df_fill_mean['feature1'].mean(), inplace=True)
df_fill_mean['feature2'].fillna(df_fill_mean['feature2'].mean(), inplace=True)
print("\n使用均值填充后的数据:")
print(df_fill_mean)

# 策略三:使用中位数填充(适用于受异常值影响的数据)
df_fill_median = df_missing.copy()
df_fill_median['feature1'].fillna(df_fill_median['feature1'].median(), inplace=True)
df_fill_median['feature2'].fillna(df_fill_median['feature2'].median(), inplace=True)
print("\n使用中位数填充后的数据:")
print(df_fill_median)

# 策略四:使用众数填充(适用于分类变量)
df_fill_mode = df_missing.copy()
df_fill_mode['category'].fillna(df_fill_mode['category'].mode()[0], inplace=True)
print("\n使用众数填充后的数据(针对分类变量):")
print(df_fill_mode)

# 策略五:插值法填充(主要用于时间序列数据或具有一定趋势的数据)
# 此处以 feature1 为例进行线性插值
df_interpolate = df_missing.copy()
df_interpolate['feature1'] = df_interpolate['feature1'].interpolate(method='linear')
print("\n使用插值法填充后的数据(线性插值):")
print(df_interpolate)

使用插值法填充后的数据(线性插值):

对 feature1,缺失值(索引2)被前后两个有效值 2 与 4 线性插值填充为 3.0; 对 feature2,索引0处为 NaN,位于边界位置,线性插值默认不外推,因此保持 NaN; category 列未处理,依然保留原样。


示例代码 2:使用 scikit-learn 的 SimpleImputer 进行填充

SimpleImputer 类可以自动应用多种填充策略,并适用于数值型和分类型数据。下面展示如何利用 SimpleImputer 分别采用中位数和众数策略进行填充。

from sklearn.impute import SimpleImputer

# 对数值型特征采用中位数策略进行填充
num_imputer = SimpleImputer(strategy='median')
# 选取数值型列进行填充,这里为 'feature1' 和 'feature2'
df_numeric = df_missing[['feature1', 'feature2']]
df_numeric_imputed = num_imputer.fit_transform(df_numeric)
df_missing[['feature1', 'feature2']] = df_numeric_imputed

print("\n使用 SimpleImputer(中位数)填充后的数值型数据:")
print(df_missing[['feature1', 'feature2']])

# 对分类变量采用众数策略进行填充
cat_imputer = SimpleImputer(strategy='most_frequent')
df_cat = df_missing[['category']]
df_cat_imputed = cat_imputer.fit_transform(df_cat)
df_missing[['category']] = df_cat_imputed

print("\n使用 SimpleImputer(众数)填充后的分类数据:")
print(df_missing[['category']])

补充说明

  1. 选择填充策略时的注意事项
      - 填充前建议对数据进行可视化和描述性统计分析,明确数据的分布特征。
      - 对于数值型变量,若数据存在极端值,使用中位数填充通常比均值填充更稳健。
      - 分类变量的填充可以通过众数、固定值或引入新的类别(如 “Missing”)实现。

  2. 工具与方法说明
      - Pandas fillna():是 Pandas 内置的缺失值填充函数,适用于快速实现简单填充策略。
      - SimpleImputer:来自 scikit-learn 的预处理模块,提供更灵活的填充策略,尤其在构建数据处理流水线时非常有用。
      - 插值方法:在时间序列分析中尤为常见,除了线性插值外,还有多项式插值、时间插值等方法可供选择。


总结

本文详细讲解了数据清洗与预处理的核心步骤:

  1. 数据抽样:通过随机抽样和分层抽样确保样本具有代表性。
  2. 数据分割:利用训练集、验证集和测试集的划分为后续模型训练、调参与评估提供支持。
  3. 异常值处理:通过 IQR 方法检测异常值,并提供删除(或替换)的策略。
  4. 缺失值处理:识别数据中的缺失情况,采用删除或填充(均值、中位数、众数、插值等)方法补全数据。

通过结合 Pandas、NumPy、scikit-learn 以及 SimpleImputer 等工具,您可以在 Jupyter Notebook 中构建出一套完整的数据预处理流程,为后续的数据挖掘和机器学习任务打下坚实基础。希望本文能帮助您深入理解数据清洗与预处理的实践步骤,并在项目中取得良好效果。


http://www.kler.cn/a/582925.html

相关文章:

  • 每天一道算法题【蓝桥杯】【下降路径最小和】
  • [多线程]基于阻塞队列(Blocking Queue)的生产消费者模型的实现
  • FPGA学习(三)——LED流水灯
  • 大数据实时分析:ClickHouse、Doris、TiDB 对比分析
  • 交通工具驱动电机技术解析:电瓶车、汽车、地铁与高铁的电机对比
  • 达梦数据库-学习-10-SQL 注入 HINT 规则(固定执行计划)
  • Redis Sentinel (哨兵模式)深度解析:构建高可用分布式缓存系统的核心机制
  • AI+Mermaid 制作流程图
  • 聚类中的相似矩阵和拉普拉斯矩阵
  • 计算机操作系统
  • Redis-缓存穿透击穿雪崩
  • 常见的交换机端口类型
  • k8s面经
  • 如何将错误边界与React的Suspense结合使用?
  • 随机快速排序
  • 我与DeepSeek读《大型网站技术架构》(12)-网购秒杀系统架构设计案例分析
  • JVM学习-类文件结构 类加载
  • FX-std::vector
  • Postgresql中null值和空字符串举例详解例子解析
  • SpringBoot 实现接口数据脱敏