🏠 首页 攻略 CSV数据清洗实战:5步搞定脏数据,附Python代码模板

CSV数据清洗实战:5步搞定脏数据,附Python代码模板

CSV文件总有缺失值、重复行、格式混乱?本文用Python+pandas手把手演示数据清洗全流程,从读取到导出干净数据,附可复用的代码模板。

写在前面的话

你导出的CSV文件,是不是经常这样:

  • 有的行只有5列,有的行有8列
  • 姓名列里混着空格、emoji、特殊符号
  • 日期格式乱七八糟——“2024-01-01”、“2024/01/01”、“2024年1月1日"全都有
  • 价格列混着人民币符号”¥“和单位"元”

我遇到过一次,一个同事从Excel导出的CSV文件,有3列数据被塞进了一个单元格,用逗号分隔,但逗号本身也是数据的一部分——CSV被CSV了

这种数据叫脏数据。不清洗,直接拿去分析,结果全是错的。

这篇文章不讲理论,直接上代码。5个步骤,帮你从一团糟的CSV变成干净可用的数据。


准备工作:你需要什么

我用 Python + pandas,因为:

  1. pandas 是数据分析的事实标准
  2. 数据清洗的80%操作都能在pandas里完成
  3. 代码可读性强,改改就能复用

如果你还没装:

pip install pandas openpyxl

第一步:读取CSV并了解数据全貌

很多新手直接pd.read_csv()就完了。别这样。先看看数据长什么样。

import pandas as pd

# 读取CSV,先只看前10行
df = pd.read_csv("data.csv", nrows=10)

# 快速诊断
print(f"数据形状: {df.shape}")
print(f"列名: {list(df.columns)}")
print(f"列类型:\n{df.dtypes}")
print(f"缺失值统计:\n{df.isnull().sum()}")

输出长这样:

数据形状: (10, 6)
列名: ['id', 'name', 'email', 'date', 'price', 'category']
列类型:
id           int64
name        object
email       object
date        object
price       object
category    object

缺失值统计:
id            0
name          1
email         2
date          0
price         3
category      0

看出来了:email有2个空值,price有3个空值,name有1个空值。


第二步:处理缺失值

缺失值不能直接删——除非缺的比例很低。一般超过5%的缺失,建议填充而不是删除。

# 先算一下缺失比例
missing_pct = df.isnull().sum() / len(df) * 100
print(missing_pct[missing_pct > 0])

处理方式按数据类型分:

数据类型处理方式适用场景
数值型中位数填充有极端值时用中位数,不用均值
分类列众数填充选出现频率最高的类别
文本列“Unknown"填充或者留空字符串”"
# 数值列用中位数填充
df['price'] = df['price'].fillna(df['price'].median())

# 分类列用众数填充
df['category'] = df['category'].fillna(df['category'].mode()[0])

# 文本列留空
df['name'] = df['name'].fillna('')

注意: 如果你的price列里有非数字字符(比如"¥100元"),需要先清洗再填充,否则会报错。


第三步:处理重复行

重复是CSV导出最常见的bug。特别是从多个系统导数据合并的时候。

# 看有多少重复
print(f"总行数: {len(df)}")
print(f"去重后: {df.drop_duplicates().shape[0]}")
print(f"重复行数: {len(df) - df.drop_duplicates().shape[0]}")

输出:

总行数: 5000
去重后: 4872
重复行数: 128

128条重复!如果拿去算月度报表,收入会虚高2.6%。

# 去重——保留第一条出现的数据
df = df.drop_duplicates()

# 如果只需要某些列作为去重依据
df = df.drop_duplicates(subset=['email', 'date'])

第四步:清洗文本列

这是最折腾的一步。CSV里的文本数据往往千奇百怪。

4.1 去除首尾空格

# 给所有字符串列去空格
for col in df.select_dtypes(include='object').columns:
    df[col] = df[col].str.strip()

4.2 统一日期格式

# pandas的to_datetime能自动识别多种格式
df['date'] = pd.to_datetime(df['date'], errors='coerce')

# errors='coerce' 会把无法解析的变成 NaT(Not a Time)
print(df['date'].isnull().sum(), "行日期无法解析")

4.3 清洗价格列

# 去掉"¥"、"元"、"人民币"等非数字字符
import re
df['price'] = df['price'].astype(str).apply(
    lambda x: re.sub(r'[^\d.]', '', x)
)
# 转成浮点数
df['price'] = pd.to_numeric(df['price'], errors='coerce')

4.4 处理大小写不一致

# 分类列统一小写
df['category'] = df['category'].str.lower().str.strip()

# 或者首字母大写
df['category'] = df['category'].str.title()

第五步:数据验证和导出

清洗完了别急着用。先验证一下。

# 检查还有没有null值
print("剩余缺失值:")
print(df.isnull().sum())

# 检查数值列范围
print("\n价格统计:")
print(df['price'].describe())

# 检查日期范围
print("\n日期范围:")
print(df['date'].min(), "至", df['date'].max())

验证通过,导出干净的CSV:

# 导出
df.to_csv("cleaned_data.csv", index=False)

# 或者导出为Excel(需要openpyxl)
df.to_excel("cleaned_data.xlsx", index=False)

完整代码模板

把上面所有步骤串起来,一份可以直接复用的模板:

import pandas as pd
import re

# 1. 读取
df = pd.read_csv("raw_data.csv")

# 2. 去重
df = df.drop_duplicates()

# 3. 填充缺失值
for col in df.select_dtypes(include='number').columns:
    df[col] = df[col].fillna(df[col].median())
df = df.fillna('')

# 4. 清洗文本
for col in df.select_dtypes(include='object').columns:
    df[col] = df[col].astype(str).str.strip()

# 5. 日期格式化
if 'date' in df.columns:
    df['date'] = pd.to_datetime(df['date'], errors='coerce')

# 6. 导出
df.to_csv("cleaned_data.csv", index=False)
print("✅ 清洗完成,共", len(df), "行")

把这个脚本保存成clean_csv.py,以后有脏数据就跑一次。


进阶:用我站的在线工具配合

如果你的数据量不大(10万行以下),其实不需要写代码。

我站提供了几个可以直接在线使用的工具:

代码适合批量、自动化、大规模处理。在线工具适合快速看一眼、小批量处理、不想装环境的时候用。


总结

CSV数据清洗的核心思路就四句话:

  1. 先读后洗——先看数据全貌,再动手改
  2. 先数量后质量——去重和填缺失是优先级最高的
  3. 先整体后局部——统一格式化(日期、大小写)优于逐个字段改
  4. 洗了要验——导出前检查一遍缺失值和范围

按这个顺序走,90%的CSV脏数据都能搞定。

剩下的10%,通常是数据源本身就有问题——那种情况建议跟数据提供方聊,别自己在代码里疯狂打补丁。