Python数据分析案例:如何高效清洗数据?从入门到实战的完整指南
目录导读
数据清洗的重要性与常见问题 {#1}
在数据分析项目中,有一句老话广为人知:“数据科学家80%的时间都在清洗数据,剩下的20%用来抱怨数据清洗。”这句话道出了数据清洗在实际工作中的核心地位,无论是机器学习建模、商业报表生成,还是可视化分析,数据的质量直接决定分析结果的可靠性。

常见的数据问题包括:
- 缺失值:字段中存在空值,比如用户未填写年龄、商品缺货标记等。
- 重复数据:同一记录出现多次,可能导致统计偏差。
- 异常值:比如订单金额为负数、年龄为200岁等明显不合理的数据。
- 格式不一致:日期格式混用(2023-1-1 vs 2023/01/01)、单位不一致(元 vs 万元)等。
- 无效文本:包含拼写错误、多余空格、特殊符号等。
核心观点:如果不先清洗数据,后续的分析将“垃圾进,垃圾出”(Garbage In, Garbage Out),掌握Python数据清洗是每个数据分析师的必修课。
Python数据清洗必备工具库 {#2}
在Python生态中,以下三个库是数据清洗的“三驾马车”:
| 库名 | 主要用途 | 特点 |
|---|---|---|
| Pandas | 结构化数据处理 | 提供DataFrame、缺失值处理、去重、过滤等函数 |
| NumPy | 数值计算与数组操作 | 处理缺失值(NaN)、随机数、数学运算 |
| 正则表达式(re) | 文本模式匹配与替换 | 清理不规则字符串、提取关键信息 |
快速安装:
pip install pandas numpy
温馨提示:Jupyter Notebook是初学者最推荐的环境,可以分步查看清洗效果。
实战案例:电商销售数据清洗全过程 {#3}
假设我们有一份某电商平台2024年1月的销售数据(sales.csv),包含以下列:
order_id:订单编号customer_name:客户姓名product:商品名称price:销售单价(元)quantity:购买数量order_date:下单日期region:地区
1 导入数据并初步浏览
import pandas as pd
import numpy as np
import re
# 读取数据
df = pd.read_csv('sales.csv')
print(df.head()) # 查看前5行
print(df.info()) # 查看数据类型、非空值数量
print(df.describe()) # 数值列统计摘要
2 发现的问题(模拟原始数据)
通过df.isnull().sum()查看缺失值,发现:
customer_name有12个空值price有5个空值quantity有一行值为0(不合理)order_date格式参差不齐,有“2024-01-05”、“2024/1/15”、“20240120”三种region列中出现“北京市/北京/beijing”三种写法- 存在完全重复的订单行
关键清洗步骤详解与代码示例 {#4}
1 处理缺失值
策略1:删除缺失行(适用于缺失比例低的情况)
df_clean = df.dropna(subset=['customer_name'])
策略2:填充缺失值(适用于有合理估计的情况)
# 用同一商品的平均价格填充price缺失
mean_price = df.groupby('product')['price'].transform('mean')
df['price'].fillna(mean_price, inplace=True)
策略3:前向/后向填充(适用于时间序列)
df['price'].fillna(method='ffill', inplace=True) # 用上一个值填充
问答:问:什么时候该删除,什么时候该填充?
答:如果缺失数据少于总样本的5%,且缺失是随机的,可以删除,但如果缺失集中在关键字段(如价格),且数据量少,建议用均值、中位数或同类别均值填充。
2 去除重复数据
# 检查重复行 print(df.duplicated().sum()) # 去除完全重复的行 df_clean = df.drop_duplicates() # 去除基于特定列的重复,保留最后一次记录 df_clean = df.drop_duplicates(subset=['order_id'], keep='last')
3 处理异常值
通过IQR方法检测异常:
Q1 = df['price'].quantile(0.25) Q3 = df['price'].quantile(0.75) IQR = Q3 - Q1 lower_bound = Q1 - 1.5 * IQR upper_bound = Q3 + 1.5 * IQR # 过滤异常价格(如负数) df_clean = df[(df['price'] >= lower_bound) & (df['price'] <= upper_bound)] # 单独处理数量为0或负数的情况 df_clean = df_clean[df_clean['quantity'] > 0]
4 统一格式
日期格式标准化:
def clean_date(date_str):
# 统一替换分隔符
date_str = re.sub(r'[\/\.]', '-', str(date_str))
# 处理无分隔符日期,如20240120
if len(date_str) == 8 and date_str.isdigit():
date_str = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:]}"
return date_str
df['order_date'] = df['order_date'].apply(clean_date)
df['order_date'] = pd.to_datetime(df['order_date'])
地区名称统一:
region_map = {
'北京': '北京市', 'beijing': '北京市', 'BJ': '北京市',
'上海': '上海市', 'shanghai': '上海市',
# 其他省份同理
}
df['region'] = df['region'].str.strip().replace(region_map)
5 文本清理(去除空格、特殊符号)
# 去除客户姓名前后的空格 df['customer_name'] = df['customer_name'].str.strip() # 去除商品名称中的多余符号 df['product'] = df['product'].str.replace(r'[^\w\u4e00-\u9fff]', '', regex=True) # 说明:\w代表字母数字,\u4e00-\u9fff代表中文字符
6 最终检查与保存
print("清洗后数据信息:")
print(df_clean.info())
print(f"清洗后数据行数:{len(df_clean)}")
print(f"缺失值统计:\n{df_clean.isnull().sum()}")
# 输出清洗后的文件
df_clean.to_csv('sales_cleaned.csv', index=False, encoding='utf-8-sig')
常见问答与避坑指南 {#5}
Q1:清洗数据时,要不要修改原始数据文件?
答:建议不要直接修改原始文件,正确的做法是:
- 保留原始文件作为备份。
- 建立清洗过程的可重复脚本(即本案例中的Python代码)。
- 输出清洗后的副本(如
sales_cleaned.csv),这样当数据更新时,只需重新运行脚本即可。
Q2:如何判断一个值是不是异常值?
答:除了使用IQR或标准差法,还要结合业务知识。
- 商品价格不可能为负数。
- 单笔订单购买数量通常不会超过1000(除非批发)。
- 订单日期不能是未来时间。 最佳实践:先用统计方法初筛,再请业务人员参与判断。
Q3:大量数据(百万级以上)如何清洗?
答:Pandas在处理百万级数据时,内存消耗较大,可以:
- 使用
chunksize分块读取。 - 使用
dtype参数指定列类型以减少内存。 - 考虑Dask、Polars等大数据框架。
- 先用SQL在数据库层面完成初步过滤。
Q4:正则表达式写起来太复杂,有没有替代方案?
答:对于特定的字符清理,可以先用str.strip()、str.replace('旧文本','新文本')解决80%的问题,真正需要正则时,可以从网上找现成模式(如匹配邮箱、手机号),或者使用pandas.Series.str.extract提取关键部分。
避坑提醒:
- 不要在循环中逐行修改DataFrame,尽量使用向量化操作(如
df['col'].apply())。 - 处理缺失值时,先备份原列,避免不可逆覆盖。
- 日期时间处理时,要注意时区问题(特别是跨国数据)。
- 清洗后的数据记得做交叉验证:比如检查
price * quantity是否等于总金额(如果有)。
数据清洗不是一次性的工作,而应该成为数据分析流程中的标准化步骤,通过本文的Python实战案例,你已经学会了如何使用Pandas处理缺失值、重复数据、异常值、格式不一致等核心问题,好的数据清洗就像画画的打底,底子越干净,后续分析越出彩,建议将本文中的代码封装成函数,形成你自己的“数据清洗流水线”,让每一次分析都从可靠的数据开始。