数据清理——确保数据质量的关键步骤

简介

在数据分析和机器学习中,数据清理是预处理过程中的重要一环。良好的数据清理能够提高数据的质量,从而提升模型的准确性和可靠性。本篇文章将深入探讨数据清理的几个关键知识点,包括缺失值处理、数据不一致问题和噪声处理。通过详细的概念解释、丰富的案例分析和逐步的代码示例,帮助初学者掌握数据清理的实用技巧。


1. 缺失值处理

由于各种原因,许多现实世界的数据集包含缺失值,通常编码为空白、NaN 或其他占位符。然而,这样的数据集与 scikit-learn 估计器不兼容,后者假设数组中的所有值都是数值,并且都具有并保留意义。
使用不完整数据集的基本策略是丢弃包含缺失值的整行和/或整列。然而,这样做的代价是丢失可能有价值的数据(即使不完整)。更好的策略是估算缺失值,可以使用提供的常量值来估算缺失值,或者使用缺失值所在的每列的统计数据(平均值、中位数或最常见值)。

1.1 均值填充

均值填充是将缺失值用该特征(列)的均值来替代。适用于数据分布较为均匀的情况。

1.1.1 使用fillna()函数用于填充缺失值

示例代码

import pandas as pd
import numpy as np

# 创建示例数据
data = pd.DataFrame({
    '年龄': [25, 30, np.nan, 35, 40],
    '收入': [50000, 70000, 80000, np.nan, 110000]
})

# 查看原始数据
print("原始数据:")
print(data)

# 使用均值填充缺失值
data['年龄'] = data['年龄'].fillna(data['年龄'].mean())
data['收入'] = data['收入'].fillna(data['收入'].mean())

print("\n均值填充后的数据:")
print(data)

输出结果:

原始数据:
    年龄       收入
0  25.0  50000.0
1  30.0  70000.0
2   NaN  80000.0
3  35.0      NaN
4  40.0  110000.0

均值填充后的数据:
    年龄       收入
0  25.0   50000.0
1  30.0   70000.0
2  32.5   80000.0
3  35.0   77500.0
4  40.0  110000.0
1.1.2 使用SimpleImputer类提供了用于估算缺失值的基本策略

示例代码

import numpy as np
from sklearn.impute import SimpleImputer
imp = SimpleImputer(missing_values=np.nan, strategy='mean') 
imp.fit([[1, 2], [np.nan, 3], [7, 6]])  #fit表示训练,X表示训练数据集
X = [[np.nan, 2], [6, np.nan], [7, 6]]
print(imp.transform(X)) #transform表示转换,X表示待转换数据集

输出结果:

[[4.         2.        ]
 [6.         3.66666667]
 [7.         6.        ]]
1.2 直接去掉

缺失值占总数据量的比例较小时,可以选择直接删除含缺失值的行或列。

示例代码
import pandas as pd
import numpy as np

# 创建示例数据
data = pd.DataFrame({
    '年龄': [25, 30, np.nan, 35, 40],
    '收入': [50000, 70000, 80000, np.nan, 110000]
})
# 删除含缺失值的行
data_dropna = data.dropna()
print("\n删除缺失值后的数据:")
print(data_dropna)

输出结果:

删除缺失值后的数据:
     年龄        收入
0  25.0   50000.0
1  30.0   70000.0
4  40.0  110000.0

2. 数据不一致问题

数据不一致是指数据集中存在相互矛盾或不符合逻辑的信息。例如,年龄和出生日期不一致,可能导致分析结果不准确。

2.1 生日和年龄不一致

可以定义一个映射函数,根据生日计算年龄,然后用该函数遍历整个数据集,并对不一致的数据进行修改或替换。

示例代码
  • 定义一个函数用于计算实际年龄,将字符串的生日转换为datetime的日期对象datetime.strptime(birthdate, "%d/%m/%Y"),再与当前日期datetime.now()进行比较,计算实际年龄。
def calculate_age(birthdate, reference_date=None):
    # 将字符串的生日转换为 datetime 对象
    birthdate = datetime.strptime(birthdate, "%d/%m/%Y")
    # 如果没有提供参考日期,则使用当前日期
    if reference_date is None:
        reference_date = datetime.now()
    # 计算年龄
    age = reference_date.year - birthdate.year - ((reference_date.month, reference_date.day) < (birthdate.month, birthdate.day))
    return age
  • 定义映射函数,检查年龄是否匹配,不匹配则用计算的年龄替换。
def correct_age(row):
    calculated_age = calculate_age(row['Birthdate'])
    # 如果年龄与生日计算的不一致,则用计算的年龄替换
    if row['Age'] != calculated_age:
        return calculated_age
    return row['Age']

  • 遍历整个数据集,并对不一致的数据进行修改或替换。示例代码:
import pandas as pd
from datetime import datetime

# 假设数据是这样的一部分
data = pd.DataFrame({
    'Age': [42, 30, 25, 40],
    'Birthdate': ['03/07/1997', '01/01/1993', '06/12/1998', '04/05/1983']
})
print('原始数据:\n', data)

# 定义一个函数计算实际年龄
def calculate_age(birthdate, reference_date=None):
    # 将字符串的生日转换为 datetime 对象
    birthdate = datetime.strptime(birthdate, "%d/%m/%Y")
    # 如果没有提供参考日期,则使用当前日期
    if reference_date is None:
        reference_date = datetime.now()
    # 计算年龄
    age = reference_date.year - birthdate.year - ((reference_date.month, reference_date.day) < (birthdate.month, birthdate.day))
    return age

# 定义映射函数,检查年龄是否匹配,不匹配则用计算的年龄替换
def correct_age(row):
    calculated_age = calculate_age(row['Birthdate'])
    # 如果年龄与生日计算的不一致,则用计算的年龄替换
    if row['Age'] != calculated_age:
        return calculated_age
    return row['Age']

# 应用函数修改数据
# apply 方法:对 DataFrame 的每一行应用 correct_age 函数进行处理
data['Age'] = data.apply(correct_age, axis=1)

print('修正后数据:\n', data)

输出结果:

原始数据:
    Age   Birthdate
0   42  03/07/1997
1   30  01/01/1993
2   25  06/12/1998
3   40  04/05/1983
修正后数据:
    Age   Birthdate
0   27  03/07/1997
1   31  01/01/1993
2   25  06/12/1998
3   41  04/05/1983

3. 噪声处理

在数据处理过程中,噪声数据指的是那些偏离正常模式的数据点,这些数据点可能是由于输入错误、传感器故障或极端的异常值。常见的处理方法有如统计检测异常值、根据业务规则过滤、离群点删除等。

3.1 自定义临界点

对于某些特征,可以设置合理的上限值,超出该值的记录被认为是噪声。

示例代码

import pandas as pd
import numpy as np

# 创建一个包含噪声的示例数据集
data = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
    'Salary': [50000, 60000, 70000, 2000000, 65000]  # David 的工资是噪声数据
})

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

# 假设合理的工资范围是 0 到 100000,我们可以根据这个阈值去掉噪声数据
salary_threshold = 100000
data_cleaned = data[data['Salary'] <= salary_threshold]

print("\n清除噪声后的数据:")
print(data_cleaned)

输出结果:

原始数据:
      Name   Salary
0    Alice    50000
1      Bob    60000
2  Charlie    70000
3    David  2000000
4      Eve    65000

清除噪声后的数据:
      Name  Salary
0    Alice   50000
1      Bob   60000
2  Charlie   70000
4      Eve   65000
3.2 离群点删除

离群点是指在数据集中与其他数据点差距较大的值,它们可能对统计分析和模型构建产生不利影响。可以使用z-score方法或IQR方法来检测离群点,并将其删除。

IQR方法

IQR(Interquartile Range)方法是基于四分位数来判断离群点。计算上四分位数(Q3)和下四分位数(Q1),并通过 IQR(Q3 - Q1)来定义上下限。
在这里插入图片描述

示例代码

import pandas as pd
import numpy as np

# 创建一个包含噪声的示例数据集
data = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
    'Salary': [50000, 60000, 70000, 2000000, 65000]  # David 的工资是噪声数据
})

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

# 计算四分位数
Q1 = data['Salary'].quantile(0.25)
Q3 = data['Salary'].quantile(0.75)
IQR = Q3 - Q1

# 定义上下限(通常用 1.5 倍 IQR)
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 过滤掉异常值
data_cleaned_stat = data[(data['Salary'] >= lower_bound) & (data['Salary'] <= upper_bound)]

print("\n基于 IQR 清除噪声后的数据:")
print(data_cleaned_stat)

输出结果:

原始数据:
      Name   Salary
0    Alice    50000
1      Bob    60000
2  Charlie    70000
3    David  2000000
4      Eve    65000

基于 IQR 清除噪声后的数据:
      Name  Salary
0    Alice   50000
1      Bob   60000
2  Charlie   70000
4      Eve   65000

总结

数据清理是数据预处理的核心步骤,它能够显著提高数据的质量。通过处理缺失值、解决数据不一致问题和清理噪声数据,可以为后续的分析和建模奠定坚实的基础。希望这篇文章能帮助大家掌握数据清理的基本概念和实用技巧,提升数据处理能力。

如有任何问题或讨论,欢迎留言!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wcyd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值