人工智能之数据分析 Pandas
第六章 数据清洗
文章目录
- [人工智能之数据分析 Pandas](#人工智能之数据分析 Pandas)
- 前言
- [🧹 一、为什么需要数据清洗?](#🧹 一、为什么需要数据清洗?)
- [🔍 二、数据概览:清洗前的第一步](#🔍 二、数据概览:清洗前的第一步)
- [🚫 三、处理缺失值(Missing Values)](#🚫 三、处理缺失值(Missing Values))
- [1. 识别缺失值](#1. 识别缺失值)
- [2. 处理策略与方法](#2. 处理策略与方法)
- [✅ 删除缺失](#✅ 删除缺失)
- [✅ 填充缺失](#✅ 填充缺失)
- [✅ 插值(适用于连续变量)](#✅ 插值(适用于连续变量))
- [🔄 四、处理重复值(Duplicates)](#🔄 四、处理重复值(Duplicates))
- [1. 检测重复](#1. 检测重复)
- [2. 删除重复](#2. 删除重复)
- [⚠️ 五、处理异常值(Outliers)](#⚠️ 五、处理异常值(Outliers))
- [1. 检测方法](#1. 检测方法)
- [IQR 方法示例:](#IQR 方法示例:)
- [2. 处理策略](#2. 处理策略)
- [🧩 六、数据类型修正](#🧩 六、数据类型修正)
- [1. 常见问题](#1. 常见问题)
- [2. 修正方法](#2. 修正方法)
- [📏 七、格式标准化与单位统一](#📏 七、格式标准化与单位统一)
- [1. 字符串清洗(使用 `.str` 访问器)](#1. 字符串清洗(使用
.str访问器))- [2. 单位统一](#2. 单位统一)
- [🗂️ 八、列与行的结构调整](#🗂️ 八、列与行的结构调整)
- [1. 重命名列](#1. 重命名列)
- [2. 删除无用列](#2. 删除无用列)
- [3. 重排列顺序](#3. 重排列顺序)
- [4. 行过滤(基于业务规则)](#4. 行过滤(基于业务规则))
- [🧪 九、清洗后验证](#🧪 九、清洗后验证)
- [🧰 十、高级技巧与工具推荐](#🧰 十、高级技巧与工具推荐)
- [✅ 总结:数据清洗 Checklist](#✅ 总结:数据清洗 Checklist)
- 后续
- 资料关注
前言
数据清洗(Data Cleaning) 是数据分析中最关键、最耗时的环节,通常占整个分析流程的 60%~80% 时间。Pandas 提供了强大而灵活的工具来高效完成这项任务。
本文将从 缺失值、重复值、异常值、数据类型、格式标准化、文本清洗、列/行操作 等维度,系统、详细、实战化地介绍 Pandas 数据清洗的核心方法与技巧。
🧹 一、为什么需要数据清洗?
真实世界的数据往往存在以下问题:
- 缺失值(
NaN,NULL, 空字符串) - 重复记录
- 错误或异常值(如年龄为 -5、工资为 1 亿)
- 数据类型不一致(数字存为字符串)
- 格式混乱(日期格式多样、单位不统一)
- 噪声数据(乱码、特殊符号)
- 列名/值命名不规范
✅ 目标 :将"脏数据"转化为结构清晰、类型正确、逻辑合理、可直接用于分析的干净数据。
🔍 二、数据概览:清洗前的第一步
在动手清洗前,先全面了解数据:
python
import pandas as pd
import numpy as np
df = pd.read_csv('dirty_data.csv')
# 基本信息
print(df.shape) # (行数, 列数)
print(df.dtypes) # 每列类型
print(df.info()) # 非空计数 + 内存
print(df.describe()) # 数值列统计
print(df.head()) # 查看前几行
# 缺失值分布
print(df.isnull().sum()) # 每列缺失数量
print((df.isnull().sum() / len(df)) * 100) # 缺失百分比
# 唯一值 & 频次(用于发现异常类别)
for col in df.select_dtypes(include='object').columns:
print(f"{col}:\n{df[col].value_counts(dropna=False)}\n")
🚫 三、处理缺失值(Missing Values)
1. 识别缺失值
Pandas 将以下视为缺失:
np.nanNonepd.NaT(时间缺失)- 读取时通过
na_values指定的值(如'N/A','-')
python
df.isnull() # 返回布尔 DataFrame
df.isna() # 同 isnull()
2. 处理策略与方法
| 策略 | 方法 | 适用场景 |
|---|---|---|
| 删除 | dropna() |
缺失比例高、无法填补 |
| 填充 | fillna() |
有合理填充值 |
| 插值 | interpolate() |
时间序列或有序数据 |
| 标记 | 新增列标识是否缺失 | 保留缺失信息用于建模 |
✅ 删除缺失
python
# 删除含任意缺失的行(默认)
df_clean = df.dropna()
# 删除所有值都缺失的行
df.dropna(how='all')
# 删除某列缺失的行
df.dropna(subset=['age'])
# 删除缺失超过阈值的列
df.dropna(axis=1, thresh=len(df)*0.8) # 保留至少 80% 非空的列
✅ 填充缺失
python
# 填充固定值
df.fillna(0) # 数值填 0
df.fillna('Unknown') # 分类填 'Unknown'
# 填充统计量
df['salary'].fillna(df['salary'].mean(), inplace=True)
df['city'].fillna(df['city'].mode()[0], inplace=True) # 众数
# 前向/后向填充(时间序列常用)
df.fillna(method='ffill') # forward fill
df.fillna(method='bfill') # backward fill
# 按组填充(更合理!)
df['salary'] = df.groupby('department')['salary'].transform(
lambda x: x.fillna(x.mean())
)
✅ 插值(适用于连续变量)
python
df['temperature'].interpolate(method='linear') # 线性插值
df['price'].interpolate(method='time') # 按时间索引插值
💡 建议 :避免简单全局均值填充,优先考虑分组填充 或模型预测填充(如 KNNImputer)。
🔄 四、处理重复值(Duplicates)
1. 检测重复
python
# 全行重复
df.duplicated().sum() # 重复行数
df[df.duplicated()] # 查看重复行(保留首次出现)
# 指定列重复
df.duplicated(subset=['user_id'])
2. 删除重复
python
# 保留首次出现(默认)
df.drop_duplicates(inplace=True)
# 保留最后一次
df.drop_duplicates(keep='last', inplace=True)
# 基于特定列去重
df.drop_duplicates(subset=['email'], keep='first')
⚠️ 注意:去重前确认业务逻辑------有些"重复"可能是合法的(如多次购买记录)。
⚠️ 五、处理异常值(Outliers)
异常值 ≠ 错误值,需结合业务判断。
1. 检测方法
- 统计法:3σ 原则(正态分布)、IQR(四分位距)
- 可视化:箱线图、散点图
- 领域规则:年龄 > 150?工资 < 0?
IQR 方法示例:
python
def detect_outliers_iqr(series):
Q1 = series.quantile(0.25)
Q3 = series.quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
return (series < lower) | (series > upper)
outliers = detect_outliers_iqr(df['salary'])
print(df[outliers])
2. 处理策略
| 策略 | 方法 |
|---|---|
| 删除 | df[~outliers] |
| 截断(Winsorize) | 用上下限值替换 |
| 转换 | 对数变换 np.log(x) |
| 保留 | 若为真实极端值(如富豪收入) |
截断示例:
python
upper_limit = df['salary'].quantile(0.95)
df['salary'] = np.where(df['salary'] > upper_limit, upper_limit, df['salary'])
🧩 六、数据类型修正
错误的数据类型会导致计算错误或内存浪费。
1. 常见问题
- 数字被读成
object(因含非数字字符) - 日期未解析为
datetime - 整数含缺失 → 变为
float64
2. 修正方法
转换数值类型
python
# 强制转数字,错误变 NaN
df['price'] = pd.to_numeric(df['price'], errors='coerce')
# 指定整数类型(支持缺失)
df['user_id'] = df['user_id'].astype('Int64') # 注意大写 I
解析日期
python
df['date'] = pd.to_datetime(df['date'], errors='coerce', format='%Y-%m-%d')
# 自动推断格式(慢但灵活)
df['date'] = pd.to_datetime(df['date'], infer_datetime_format=True)
优化内存(分类变量)
python
# 将低基数字符串转为 category
df['gender'] = df['gender'].astype('category')
df['city'] = df['city'].astype('category')
# 查看内存节省
df.info(memory_usage='deep')
📏 七、格式标准化与单位统一
1. 字符串清洗(使用 .str 访问器)
python
# 去除空格
df['name'] = df['name'].str.strip()
# 大小写统一
df['email'] = df['email'].str.lower()
# 替换非法字符
df['phone'] = df['phone'].str.replace(r'\D', '', regex=True) # 只留数字
# 提取模式
df['area_code'] = df['phone'].str[:3]
# 拆分列
df[['first', 'last']] = df['full_name'].str.split(' ', expand=True)
2. 单位统一
python
# 工资单位统一为"元"
df['salary'] = np.where(
df['salary_unit'] == '千元',
df['salary'] * 1000,
df['salary']
)
🗂️ 八、列与行的结构调整
1. 重命名列
python
df.rename(columns={'old_name': 'new_name'}, inplace=True)
# 批量标准化列名
df.columns = df.columns.str.lower().str.replace(' ', '_')
2. 删除无用列
python
df.drop(['temp_col', 'id_backup'], axis=1, inplace=True)
3. 重排列顺序
python
df = df[['id', 'name', 'age', 'salary']] # 指定顺序
4. 行过滤(基于业务规则)
python
# 年龄合理范围
df = df[(df['age'] >= 0) & (df['age'] <= 120)]
# 邮箱格式校验
df = df[df['email'].str.contains('@', na=False)]
🧪 九、清洗后验证
清洗不是一次性任务,需验证结果:
python
# 再次检查缺失
assert df.isnull().sum().sum() == 0, "仍有缺失值!"
# 检查类型
assert df['age'].dtype == 'int64'
assert df['date'].dtype == 'datetime64[ns]'
# 检查唯一性
assert df['user_id'].is_unique, "user_id 不唯一!"
# 保存清洗后数据
df.to_csv('clean_data.csv', index=False)
🧰 十、高级技巧与工具推荐
| 场景 | 工具/方法 |
|---|---|
| 自动检测数据质量问题 | pandas-profiling(现 ydata-profiling) |
| 交互式清洗 | OpenRefine(外部工具) |
| 复杂文本清洗 | 正则表达式 + str.extract() |
| 批量清洗多文件 | glob + 循环 |
| 可复现清洗流程 | 封装为函数或使用 sklearn 的 Transformer |
示例:封装清洗函数
python
def clean_employee_data(df):
df = df.copy()
df.columns = df.columns.str.lower().str.replace(' ', '_')
df['salary'] = pd.to_numeric(df['salary'], errors='coerce')
df['age'] = pd.to_numeric(df['age'], errors='coerce')
df = df[(df['age'] >= 18) & (df['age'] <= 65)]
df['email'] = df['email'].str.lower().str.strip()
df = df.drop_duplicates(subset=['email'])
return df
clean_df = clean_employee_data(raw_df)
✅ 总结:数据清洗 Checklist
| 步骤 | 操作 |
|---|---|
| 1️⃣ 概览 | shape, info(), isnull().sum() |
| 2️⃣ 缺失值 | 删除 / 填充 / 插值 |
| 3️⃣ 重复值 | drop_duplicates() |
| 4️⃣ 异常值 | 检测 + 截断/删除 |
| 5️⃣ 类型修正 | to_numeric, to_datetime, astype('category') |
| 6️⃣ 格式标准化 | .str 方法清洗文本 |
| 7️⃣ 结构调整 | 重命名、删列、重排序 |
| 8️⃣ 验证 | 断言检查 + 保存 |
💡 记住 :
"垃圾进,垃圾出"(Garbage In, Garbage Out)再强大的模型也无法弥补脏数据带来的偏差。
后续
python过渡项目部分代码已经上传至gitee,后续会逐步更新。
资料关注
公众号:咚咚王
gitee:https://gitee.com/wy18585051844/ai_learning
《Python编程:从入门到实践》
《利用Python进行数据分析》
《算法导论中文第三版》
《概率论与数理统计(第四版) (盛骤) 》
《程序员的数学》
《线性代数应该这样学第3版》
《微积分和数学分析引论》
《(西瓜书)周志华-机器学习》
《TensorFlow机器学习实战指南》
《Sklearn与TensorFlow机器学习实用指南》
《模式识别(第四版)》
《深度学习 deep learning》伊恩·古德费洛著 花书
《Python深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》
《深入浅出神经网络与深度学习+(迈克尔·尼尔森(Michael+Nielsen)》
《自然语言处理综论 第2版》
《Natural-Language-Processing-with-PyTorch》
《计算机视觉-算法与应用(中文版)》
《Learning OpenCV 4》
《AIGC:智能创作时代》杜雨+&+张孜铭
《AIGC原理与实践:零基础学大语言模型、扩散模型和多模态模型》
《从零构建大语言模型(中文版)》
《实战AI大模型》
《AI 3.0》