🐸 青蛙编程网
首页 / Python / Pandas / 3. 数据清洗

数据清洗

这是什么:数据清洗 = 把缺失、重复、类型不对的脏数据收拾干净的手艺。

为什么用:拿到真实数据,第一件事不是分析,是打扫。真实数据从来不干净,缺失、重复、类型不对的混在一起;不先清理,后面统计全白搭。

如何用:本章从一份带缺失值的"脏数据"起步,先摸清缺了多少,再学 isnull、dropna、fillna 三件套。

先造一份"脏数据"练手:

import pandas as pd

data = {
    "姓名": ["小明", "小红", "小明", "小刚", None],
    "年龄": ["18", "17", "18", "19", "20"],
    "成绩": [92, None, 92, 95, 60],
}
df = pd.DataFrame(data)
print(df)
    姓名  年龄  成绩
0  小明  18  92.0
1  小红  17   NaN
2  小明  18  92.0
3  小刚  19  95.0
4  None  20  60.0

NaN(Not a Number)就是 pandas 表示"这里缺数据"的写法;成绩列因为混进了 NaN,被自动变成了小数(92.0)。

缺失值:isnull / dropna / fillna

先摸清缺了多少:

print(df.isnull().sum())   # 每列缺了几个
姓名    1
年龄    0
成绩    1
dtype: int64

处理只有两条路——删或补:

df = df.dropna(subset=["姓名"])                   # 姓名缺失的行:删(关键信息缺了没法救)
df["成绩"] = df["成绩"].fillna(df["成绩"].mean())  # 成绩缺失:用平均分补上

重复值:drop_duplicates

上面的小明出现了两次、数据完全一样,一行去重:

df = df.drop_duplicates()   # 完全重复的行只留第一条

类型转换:astype

年龄这一列存的是字符串 "18"(带引号没法算平均数),转成数字:

df["年龄"] = df["年龄"].astype(int)

改列名:rename

df = df.rename(columns={"姓名": "学生"})   # 写法:旧名: 新名

打扫完看结果

print(df)
   学生  年龄  成绩
0  小明  18  92.0
1  小红  17  93.0
3  小刚  19  95.0

对比开头:缺姓名的行没了,小红的 NaN 变成了平均分 93,小明只留一条,年龄成了数字。注意行号还是 0、1、3——pandas 保留原始行号,想重排可以加一句 df = df.reset_index(drop=True)。

本章解读

代码 作用
df.isnull().sum() 每列统计缺失数量
df.dropna(subset=[...]) 指定列有缺失就删整行
df.fillna(值) 用给定值(如平均数)填补缺失
df.drop_duplicates() 删除完全重复的行
df["列"].astype(int) 整列转换类型
df.rename(columns={旧: 新}) 改列名

记忆口诀

缺失先问 isnull,删用 dropna 补用 fillna,重复 dedup 类型 astype。

动手改

  1. 把 fillna 里的平均分改成固定值 0,看输出有什么不同
  2. 在数据里再手动复制一行重复数据,用 drop_duplicates() 验证能去掉
  3. 试试不带参数的 df.dropna(),对比 dropna(subset=["姓名"])——为什么它删的行更多?

下一章:统计与筛选,干净的数据该分析起来了 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。