数据清洗的核心在于系统性处理缺失值、重复项、格式不一致、异常值及逻辑错误,以提升数据质量。1. 缺失值可通过删除或填充处理,依据缺失比例与数据特性选择合适策略;2. 重复项需明确重复定义,使用drop_duplicates()清除;3. 格式不一致应统一大小写、去除空格,并转换为正确数据类型;4. 异常值通过统计方法(如iqr)识别,结合业务判断删除、替换或转换;5. 数据一致性检查需验证字段间逻辑关系,确保数据合理性。整个过程依赖对数据的深入理解,且通常需反复迭代。

用Python清洗杂乱数据,核心在于利用Pandas等库,系统性地处理缺失值、重复项、格式不一致及异常值,将原始的“脏数据”转化为可分析、高质量的结构化数据。这通常是数据项目中最耗时但也最关键的第一步,它直接决定了后续分析和模型训练的可靠性。

数据清洗是一个迭代的过程,没有一劳二的万能公式,更像是一场侦探游戏,需要你深入了解数据本身。我的做法通常是:先加载数据并进行初步探索,用
info()
describe()
head()
isnull().sum()
说起数据清洗,很多人第一反应就是“把数据弄干净”,但“干净”到底意味着什么?我个人的理解是,让数据变得“可用”且“可靠”。这其中要处理的“脏”东西,大致有这么几类:
立即学习“Python免费学习笔记(深入)”;

NaN
None
NA
-
识别这些问题,往往需要结合
df.info()
df.describe()
df.isnull().sum()
df.duplicated().sum()
import pandas as pd
import numpy as np
# 示例数据
data = {
'ID': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'Name': ['Alice', 'Bob', 'Charlie', 'Alice', 'David', 'Eve', 'Frank', 'Grace', 'Heidi', 'Ivan'],
'Age': [25, 30, np.nan, 25, 40, 22, 35, 28, 999, 30],
'City': ['New York', 'London', 'paris', 'New York', 'Berlin', 'London', 'Paris ', 'New York', 'London', 'Berlin'],
'Income': [50000, 60000, 75000, 50000, np.nan, 45000, 80000, 55000, 70000, 65000],
'JoinDate': ['2023-01-15', '2023/02/20', '2023-03-10', '2023-01-15', '2023-04-05', '2023-05-01', '2023-06-12', '2023-07-01', '2023-08-08', '2023-09-01']
}
df = pd.DataFrame(data)
print("--- 初始数据信息 ---")
df.info()
print("\n--- 缺失值统计 ---")
print(df.isnull().sum())
print("\n--- 重复行统计 ---")
print(f"总重复行数: {df.duplicated().sum()}")
print("\n--- 描述性统计 (发现异常值) ---")
print(df.describe())处理缺失值,这真的是数据清洗里最让人头疼也最考验经验的一环。究竟是删除含有缺失值的行或列,还是想办法填充它们?这没有绝对的答案,完全取决于你的数据量、缺失值的比例、缺失模式以及你后续的分析目的。

删除 (Dropping): 如果某个特征的缺失值比例非常高(比如超过70-80%),或者某个观察值(行)大部分数据都缺失,那么删除它们可能是最直接有效的办法。
df.dropna()
df.dropna()
df.dropna(how='all')
df.dropna(axis=1)
df.dropna(thresh=N)
df.dropna(subset=['列名1', '列名2'])
我个人在使用
dropna()
填充 (Imputation): 当缺失值比例不高,且你认为这些缺失值背后可能蕴含着某种信息时,填充是更好的选择。
df.fillna()
df['列名'].fillna(0)
df['列名'].fillna('未知')df['Age'].fillna(df['Age'].mean())
df['Age'].fillna(df['Age'].median())
df['City'].fillna(df['City'].mode()[0])
mode()
ffill
df['列名'].fillna(method='ffill')
bfill
df['列名'].fillna(method='bfill')
df['列名'].interpolate()
我的经验是,对于数值型缺失值,如果分布偏态,中位数往往是比均值更稳妥的选择。对于类别型数据,众数填充通常比较合理。对于时间序列,
ffill
bfill
# 处理缺失值示例
# 复制一份数据,避免影响后续操作
df_cleaned_missing = df.copy()
# 1. 删除缺失值:例如,如果Name缺失,则认为这条记录无效
# df_cleaned_missing.dropna(subset=['Name'], inplace=True) # 这里Name没有缺失,所以不执行
# 2. 填充缺失值
# 填充Age的缺失值:使用中位数,因为Age可能有异常值(999)
age_median = df_cleaned_missing['Age'].median()
df_cleaned_missing['Age'].fillna(age_median, inplace=True)
print(f"\n--- Age列缺失值填充后 (中位数: {age_median}) ---")
print(df_cleaned_missing['Age'])
# 填充Income的缺失值:使用均值,假设Income分布相对均匀
income_mean = df_cleaned_missing['Income'].mean()
df_cleaned_missing['Income'].fillna(income_mean, inplace=True)
print(f"\n--- Income列缺失值填充后 (均值: {income_mean:.2f}) ---")
print(df_cleaned_missing['Income'])
print("\n--- 缺失值处理后的统计 ---")
print(df_cleaned_missing.isnull().sum())数据清洗的这部分工作,就像是整理你的衣柜,把散乱的衣服叠好,把重复的款式挑出来。它看起来琐碎,但却是构建可靠数据基础的基石。
统一数据格式: 数据类型不正确,就像是把鞋子放进了帽子抽屉,用起来非常别扭。
astype()
to_datetime()
to_numeric()
category
str.lower()
str.strip()
str.replace()
City
df['City'].str.lower()
df['City'].str.strip()
df['City'].str.replace('paris', 'Paris', case=False)消除重复项 (drop_duplicates()
df.duplicated()
df.drop_duplicates()
df.drop_duplicates(inplace=True)
df.drop_duplicates(subset=['列名1', '列名2'])
ID
Name
df.drop_duplicates(keep='first')
df.drop_duplicates(keep='last')
df.drop_duplicates(keep=False)
我的建议是,在删除重复项时,一定要明确你“重复”的定义是什么。是所有列都一样才算重复,还是部分关键列一样就算重复?这直接影响你的数据完整性和后续分析。
# 复制一份数据,基于前面处理缺失值后的数据
df_final_cleaned = df_cleaned_missing.copy()
# 1. 统一数据格式
# 将JoinDate转换为datetime类型
df_final_cleaned['JoinDate'] = pd.to_datetime(df_final_cleaned['JoinDate'], errors='coerce')
# errors='coerce' 会将无法解析的日期转换为NaT (Not a Time)
# 统一City列的格式:小写并去除首尾空格
df_final_cleaned['City'] = df_final_cleaned['City'].str.lower().str.strip()
# 进一步标准化城市名称,例如 'paris' -> 'Paris'
df_final_cleaned['City'] = df_final_cleaned['City'].replace({'paris': 'Paris', 'new york': 'New York', 'london': 'London', 'berlin': 'Berlin'})
# 2. 消除重复项
# 检查基于ID和Name的重复
print(f"\n--- 基于ID和Name的重复行数量: {df_final_cleaned.duplicated(subset=['ID', 'Name']).sum()} ---")
# 发现ID=1, Name='Alice' 和 ID=4, Name='Alice' 是重复的,但ID不同,所以不是完全重复的行。
# 如果我们认为ID是唯一标识,那么ID=4的Alice是重复的(假设ID是唯一用户标识)
# 这里我们发现ID 1和4的Name都是Alice,但ID不同。
# 如果我们认为ID是唯一的,那么就没有完全重复的行。
# 如果我们认为'Name'列的'Alice'重复了,那需要更复杂的去重逻辑。
# 对于本例,我们假设整行完全重复才算。
print(f"\n--- 完全重复行数量: {df_final_cleaned.duplicated().sum()} ---")
# 发现第1行和第4行是完全重复的 (ID=1, Name='Alice', Age=25, City='New York', Income=50000.0, JoinDate='2023-01-15')
# 实际上,ID是主键,ID=1和ID=4的Alice是两个不同的人。
# 如果ID是唯一标识,那么ID=4的Alice是重复录入的ID=1的Alice,应该删除ID=4。
# 让我们假设ID是唯一标识,删除ID=4的重复记录。
# 在本例中,df中ID=1和ID=4的记录除了ID不同,其他完全一样。
# 如果我们想删除基于ID的重复,即ID唯一,那么应该删除ID=4。
# 更好的做法是,如果我们认为ID是唯一键,那么就直接删除ID列的重复。
df_final_cleaned.drop_duplicates(subset=['ID'], keep='first', inplace=True) # 确保ID唯一
print("\n--- 清洗后的数据预览 ---")
print(df_final_cleaned.head())
print("\n--- 清洗后数据信息 ---")
df_final_cleaned.info()
print("\n--- 清洗后City列唯一值 ---")
print(df_final_cleaned['City'].unique())数据清洗的最后阶段,往往是处理那些“不合群”的异常值,以及确保数据在逻辑上是自洽的。这部分工作非常依赖你对业务的理解,因为一个“异常”的数据点,可能是错误,也可能是真实的极端情况。
异常值处理 (Outlier Treatment):
Age
数据一致性检查 (Data Consistency Checks): 这超出了简单的格式统一,更多是关于数据之间的逻辑关系。
这部分通常需要编写自定义的函数或规则来执行。
# 继续在df_final_cleaned上操作
# 1. 异常值处理
# 处理Age列的异常值 (999)
# 使用IQR方法来识别和处理
Q1 = df_final_cleaned['Age'].quantile(0.25)
Q3 = df_final_cleaned['Age'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 识别异常值
outliers = df_final_cleaned[(df_final_cleaned['Age'] < lower_bound) | (df_final_cleaned['Age'] > upper_bound)]
print(f"\n--- Age列IQR方法识别的异常值: ---\n{outliers}")
# 对于Age的999,明显是录入错误,可以考虑替换为中位数或直接删除以上就是如何用Python清洗杂乱数据?预处理完整流程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号