简介
在数据分析和机器学习中,数据清理是预处理过程中的重要一环。良好的数据清理能够提高数据的质量,从而提升模型的准确性和可靠性。本篇文章将深入探讨数据清理的几个关键知识点,包括缺失值处理、数据不一致问题和噪声处理。通过详细的概念解释、丰富的案例分析和逐步的代码示例,帮助初学者掌握数据清理的实用技巧。
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_agereturn 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_agereturn 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
总结
数据清理是数据预处理的核心步骤,它能够显著提高数据的质量。通过处理缺失值、解决数据不一致问题和清理噪声数据,可以为后续的分析和建模奠定坚实的基础。希望这篇文章能帮助大家掌握数据清理的基本概念和实用技巧,提升数据处理能力。
如有任何问题或讨论,欢迎留言!