Pandas 数据清洗:从混乱到整洁的实战指南
在数据驱动的时代,我们每天都在与数据打交道。但真实世界中的数据,往往像一团乱麻——缺失值、重复项、格式不一、异常值……这些都让分析变得举步维艰。这时候,Pandas 就成了我们最可靠的助手。Pandas 不仅能高效处理结构化数据,更擅长把一团糟的数据“理顺”。今天,我们就来一起深入学习 Pandas 数据清洗 的核心技巧,让你的数据分析之路更加顺畅。
什么是 Pandas 数据清洗?
想象一下,你从一个网站导出了用户行为日志,结果发现有些用户的“年龄”字段是“未知”,有些是“25岁”,有些是“25”,还有些干脆是空的。这种数据我们称之为“脏数据”。而 Pandas 数据清洗,就是通过一系列操作,将这些不一致、不完整、不规范的数据,转化为干净、统一、可用的格式。
Pandas 提供了丰富的函数和方法,让我们可以轻松完成缺失值处理、重复数据删除、格式标准化、异常值识别等任务。掌握这些技巧,就等于掌握了数据质量的“金钥匙”。
检查数据:先看清“病灶”
在动手清洗之前,必须先“望闻问切”。我们得先了解数据的“健康状况”。
import pandas as pd
df = pd.read_csv('user_data.csv')
print(df.head())
print(df.info())
print(df.describe())
代码注释:
df.head()显示前 5 行数据,快速预览内容。df.info()提供每列的数据类型(如 int64、object)和非空值数量,帮助我们发现缺失。df.describe()对数值列生成均值、标准差、最小最大值等统计信息,是识别异常值的重要依据。
💡 小贴士:
df.info()是你每次加载数据后的第一道检查,它能快速告诉你“哪些列可能有缺失值”。
处理缺失值:别让“空”成为分析的绊脚石
缺失值(Missing Values)是数据清洗中最常见的问题。常见的表示方式有 None、NaN、空字符串 '' 等。它们会让后续的计算出错或产生误导。
识别缺失值
print(df.isnull().sum())
print(df.isnull().mean() * 100)
代码注释:
df.isnull()返回布尔值矩阵,True表示该位置是缺失值。.sum()统计每列中True的数量,即缺失值个数。.mean() * 100计算每列缺失值占比,帮助判断是否需要处理。
常见处理策略
1. 删除含缺失值的行(适用于缺失少且不重要)
df_cleaned = df.dropna()
df_cleaned = df.dropna(how='all')
代码注释:
dropna()默认删除任意一个值缺失的行。how='all'表示只有当整行全是缺失值时才删除,避免误删有效数据。
2. 填充缺失值(更常用)
df['age'].fillna(0, inplace=True)
df['age'].fillna(df['age'].mean(), inplace=True)
df['gender'].fillna(df['gender'].mode()[0], inplace=True)
df['sales'].fillna(method='ffill', inplace=True)
df['sales'].fillna(method='bfill', inplace=True)
代码注释:
fillna()是最核心的填充方法。inplace=True表示直接修改原数据,避免重新赋值。method='ffill'是“前向填充”,适合时间序列中偶尔缺失的值。
📌 建议:对于数值型数据,用均值或中位数填充;对于分类数据,用众数;对于时间序列,优先考虑前后填充。
去除重复数据:让每一行都独一无二
重复数据会严重影响统计结果。比如,一个用户在日志中被记录了两次,就会被误认为是两个独立用户。
print(df.duplicated().sum())
print(df[df.duplicated()])
df_cleaned = df.drop_duplicates()
代码注释:
duplicated()返回布尔序列,True表示该行是重复的。drop_duplicates()默认保留第一次出现的重复项,也可通过keep='last'保留最后一次。- 可指定列进行去重,如
drop_duplicates(subset=['user_id']),仅根据用户 ID 去重。
✅ 小技巧:在数据清洗流程中,去重通常是“检查 → 删除”的一步,建议放在缺失值处理之后。
标准化数据格式:让数据“整齐划一”
数据格式不一致是另一个常见问题。比如“出生日期”字段可能有 “1990-01-01”、“1990/01/01”、“01-01-1990” 等多种格式。
df['birth_date'] = pd.to_datetime(df['birth_date'], errors='coerce')
print(df['birth_date'].isnull().sum()) # 查看转换失败的数量
代码注释:
pd.to_datetime()可自动识别多种日期格式。errors='coerce'是安全选项,避免因格式错误导致程序崩溃。
字符串清洗:统一大小写与去除空格
df['gender'] = df['gender'].str.upper()
df['name'] = df['name'].str.strip()
df['name'] = df['name'].str.replace(r'\s+', ' ', regex=True)
代码注释:
.str.upper()将字符串全部转为大写。.str.strip()去除首尾空格。.str.replace(r'\s+', ' ', regex=True)使用正则表达式将多个连续空白字符替换为一个空格。
识别与处理异常值:别让“ outliers”误导你
异常值(Outliers)是明显偏离正常范围的数据点。比如,一个“年龄”是 200 岁,明显不合理。
方法一:使用统计学方法(Z-Score)
from scipy import stats
z_scores = stats.zscore(df['age'])
outliers = df[abs(z_scores) > 3]
print(outliers)
代码注释:
- Z-Score 表示数据点与均值的偏离程度(单位:标准差)。
- 通常认为 |Z| > 3 的数据为异常值。
方法二:使用四分位距(IQR)
Q1 = df['age'].quantile(0.25)
Q3 = df['age'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = df[(df['age'] < lower_bound) | (df['age'] > upper_bound)]
print(outliers)
代码注释:
- IQR 法更稳健,不依赖正态分布假设。
- 通常将低于 Q1 - 1.5×IQR 或高于 Q3 + 1.5×IQR 的值视为异常。
保存清洗后的数据:让成果“落地”
清洗完成后,别忘了保存结果,以便后续分析使用。
df_cleaned.to_csv('cleaned_user_data.csv', index=False)
代码注释:
index=False是好习惯,避免在 CSV 中多出一列“0,1,2…”的索引。- 你也可以保存为 Excel:
to_excel('cleaned_data.xlsx', index=False)。
总结:Pandas 数据清洗的核心流程
在实际项目中,Pandas 数据清洗 通常遵循以下流程:
- 加载数据 → 2. 检查缺失与重复 → 3. 处理缺失值 → 4. 去除重复项 → 5. 标准化格式 → 6. 识别异常值 → 7. 保存干净数据
这个流程就像“数据体检”——每一步都不可跳过。只有把“病灶”清除干净,后续的分析、建模、可视化才能真正发挥作用。
记住:数据质量决定分析质量。花时间做好清洗,远比花时间调模型更值。
现在,你已经掌握了 Pandas 数据清洗 的核心技能。下次面对一团乱麻的数据时,别慌,打开 Jupyter Notebook,一步一步来,你也能把它变成清晰、可靠、可用的分析资产。