Python 数据分析入门|02:Pandas 数据清洗:缺失值/重复值/异常值处理
上一篇我们用 Pandas 读取了数据,还摸清了数据的“家底”——但实际工作中,你拿到的往往是“脏数据”:比如电商订单表里“销售额”列空了几行、同一订单重复录了3次、销量突然出现10000件(明显是多输了个0)……
这些“脏数据”会直接导致分析结果出错:比如用含空值的销售额算总和,结果会是“NaN”(无意义);重复订单会让总销量虚高;异常值会拉高平均值,让你误以为业务很好。数据分析师常说“数据脏,分析再牛也白费”,今天就教你用 Pandas 搞定三大脏数据:缺失值、重复值、异常值,每个方法都附电商实战代码,可以直接用。
先搞懂:为什么数据会“脏”?(先建立认知)
在学处理方法前,先知道数据“脏”的原因,能帮你选对处理方式:
- 缺失值:用户没填信息(比如电商订单里“备注”空着)、系统故障没记录(比如收银机没保存销售额)、数据导入漏了(比如Excel里某行没复制全);
- 重复值:手动录入重复(比如电商运营重复上传同一订单)、系统bug多存了一遍(比如接口调用两次,存了两次数据);
- 异常值:录入错误(比如销量“100”写成“1000”)、特殊情况(比如电商大促时的超大订单)、数据格式错(比如把“2024-01-01”写成“2024/01/01”,但这里我们重点讲数值异常)。
今天用“电商订单数据”做案例(含真实脏数据),先教你准备数据,再一步步清洗。
第一步:准备实战数据(数据可以直接用)
我们用“电商月度订单数据”,包含6列关键信息,故意加了缺失值、重复值、异常值,新手可以:
方式1:手动建Exce
新建Excel文件命名为电商订单数据.xlsx,输入以下数据(空单元格就是缺失值,最后两行是重复订单):
| 订单号 | 日期 | 商品类别 | 销量(件) | 销售额(元) | 用户ID |
|---|---|---|---|---|---|
| OD001 | 2026-01-01 | 服饰 | 2 | 398 | U101 |
| OD002 | 2026-01-02 | 电子产品 | 1 | 1299 | U102 |
| OD003 | 2026-01-03 | 食品 | 5 | U103 | |
| OD004 | 2026-01-04 | 服饰 | 3 | 597 | |
| OD005 | 2026-01-05 | 电子产品 | 1000 | 59900 | U105 |
| OD006 | 2026-01-06 | 食品 | 4 | 88 | U106 |
| OD002 | 2026-01-02 | 电子产品 | 1 | 1299 | U102 |
| OD002 | 2026-01-02 | 电子产品 | 1 | 1299 | U102 |
方式2:代码自动生成订单数据
在pycharm里运行以下代码,会自动生成带脏数据的电商订单数据.xlsx:
import pandas as pd
import numpy as np
# 构造带脏数据的电商订单数据
data = {
"订单号": ["OD001", "OD002", "OD003", "OD004", "OD005", "OD006", "OD002", "OD002"],
"日期": ["2026-01-01", "2026-01-02", "2026-01-03", "2026-01-04", "2026-01-05", "2026-01-06", "2026-01-02", "2026-01-02"],
"商品类别": ["服饰", "电子产品", "食品", "服饰", "电子产品", "食品", "电子产品", "电子产品"],
"销量(件)": [2, 1, 5, 3, 1000, 4, 1, 1], # 1000是异常值
"销售额(元)": [398, 1299, np.nan, 597, 59900, 88, 1299, 1299], # np.nan是缺失值
"用户ID": ["U101", "U102", "U103", np.nan, "U105", "U106", "U102", "U102"] # 一个用户ID缺失
}
df = pd.DataFrame(data)
df.to_excel("电商订单数据.xlsx", index=False)
print("✅ 电商订单数据已生成,包含缺失值、重复值、异常值")
关键提醒:
确保电商订单数据.xlsx和pycharm文件在同一文件夹,避免“文件找不到”报错
核心操作1:处理缺失值(用dropna()/fillna(),2招搞定)
缺失值是最常见的脏数据,先学“怎么识别”,再学“怎么处理”。
第一步:识别缺失值(先知道哪里空了)
用info()或isnull().sum()能快速定位缺失值:
# 1. 导入Pandas,读取数据
import pandas as pd
df = pd.read_excel("电商订单数据.xlsx")
# 2. 识别缺失值
print("===== 缺失值统计 =====")
# 方法1:info()看非空值数量(空值=总行数-非空值数)
print("1. info()查看:")
print(df.info())
# 方法2:isnull().sum()直接算每列空值数(推荐新手用)
print("\n2. 每列缺失值数量:")
print(df.isnull().sum())
#####################################
运行结果解读:
===== 缺失值统计 =====
1. info()查看:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8 entries, 0 to 7
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 订单号 8 non-null object
1 日期 8 non-null object
2 商品类别 8 non-null object
3 销量(件) 8 non-null int64
4 销售额(元) 7 non-null float64 # 1个缺失值
5 用户ID 7 non-null object # 1个缺失值
dtypes: float64(1), int64(1), object(4)
memory usage: 512.0+ bytes
2. 每列缺失值数量:
订单号 0
日期 0
商品类别 0
销量(件) 0
销售额(元) 1 # 明确看到“销售额”有1个空值
用户ID 1 # “用户ID”有1个空值
dtype: int64
第二步:处理缺失值(2种方法,按需选)
缺失值不能直接留着,主要有“删除”和“填充”两种处理方式,具体要根据业务场景选:
✅ 方法1:删除缺失值(dropna())—— 适合缺失值少、不影响分析
如果某列空值很少(比如只占1%),且删除后不影响数据规模,直接删包含空值的行/列。
代码示例(删除含缺失值的行):
# 1. 删除包含缺失值的行(默认axis=0,删行;axis=1是删列,慎用!)
df_drop = df.dropna(axis=0) # df_drop是删除后的新数据框,原df不变
# 2. 验证删除结果(空值数应为0)
print("===== 删除缺失值后 =====")
print(f"原数据行数:{len(df)}")
print(f"删除后行数:{len(df_drop)}")
print("删除后每列缺失值:")
print(df_drop.isnull().sum())
#################################
运行结果:
===== 删除缺失值后 =====")
原数据行数:8
删除后行数:6 # 删了2行(因为2行有缺失值)
删除后每列缺失值:
订单号 0
日期 0
商品类别 0
销量(件) 0
销售额(元) 0
用户ID 0
dtype: int64
避坑点:别盲目删列!
初学者容易用dropna(axis=1)删列,但“销售额”列虽然有1个空值,其他7个值有用,删列会丢大量数据,除非某列90%都是空值,否则别删列。
✅ 方法2:填充缺失值(fillna())—— 适合缺失值多、不能删
如果缺失值多(比如占20%),删除会导致数据不够,就用“合理值”填充,分数值型和文本型两种。
| 数据类型 | 填充方式 | 例子 |
|---|---|---|
| 数值型 | 均值(正常分布)、中位数(偏态分布) | 销售额用同类别商品的均值填充 |
| 文本型 | 众数(出现最多的值)、固定值 | 用户ID缺失用“未知用户”填充 |
代码示例(按类型填充):
# 1.复制原数据,避免修改原数据
df_fill = df.copy()
# 2.填充数值型缺失值(销售额:用“同商品类别”的均值填充,更合理)
# 先按商品类别分组,算每组的销售额均值
category_sales_mean = df_fill.groupby("商品类别")["销售额(元)"].transform("mean")
# 用分组均值填充销售额的空值
df_fill["销售额(元)"] = df_fill["销售额(元)"].fillna(category_sales_mean)
# 3. 填充文本型缺失值(用户ID:用“未知用户”填充)
df_fill["用户ID"] = df_fill["用户ID"].fillna("未知用户")
# 4. 验证填充结果
print("===== 填充缺失值后 =====")
print("填充后的销售额列:")
print(df_fill["销售额(元)"])
print("\n填充后的用户ID列:")
print(df_fill["用户ID"])
print("\n填充后缺失值统计:")
print(df_fill.isnull().sum())
运行结果解读:
===== 填充缺失值后 ===== 填充后的销售额列: 0 398.0 1 1299.0 2 88.0 # 原空值(食品类)用食品类均值88填充(只有1个食品数据,就是88 3 597.0 4 59900.0 5 88.0 6 1299.0 7 1299.0 Name: 销售额(元), dtype: float64 填充后的用户ID列: 0 U101 1 U102 2 U103 3 未知用户 # 原空值填充为“未知用户” 4 U105 5 U106 6 U102 7 U102 Name: 用户ID, dtype: object 填充后缺失值统计: 订单号 0 日期 0 商品类别 0 销量(件) 0 销售额(元) 0 用户ID 0 dtype: int64
小技巧:
如果不想分组,简单填充可用df_fill["销售额(元)"].fillna(df_fill["销售额(元)"].mean())(用整体均值),但分组填充更贴合业务(比如服饰和电子产品的销售额差异大,不能用整体均值)。
核心操作2:处理重复值(用drop_duplicates(),1行去重)
重复值会导致统计结果虚高(比如重复订单让总销量多算2次),必须处理,步骤是“识别→去重→验证”。
第一步:识别重复值
用duplicated().sum()算重复行数,duplicated(keep=False)查看具体重复行:
df = pd.read_excel("电商订单数据.xlsx")
df_fill = df.copy()
# 用填充后的df_fill数据(也可以用原df)
print("===== 重复值统计 =====")
# 1. 统计重复行数(默认按所有列判断重复)
print(f"总重复行数:{df_fill.duplicated().sum()}")
# 2. 查看具体重复行(keep=False:所有重复行都标为True)
duplicate_rows = df_fill[df_fill.duplicated(keep=False)]
print("\n重复的行:")
print(duplicate_rows)
#########################################
执行结果:
===== 重复值统计 =====
总重复行数:2 # 有2行重复(原数据最后两行和第二行重复)
重复的行:
订单号 日期 商品类别 销量(件) 销售额(元) 用户ID
1 OD002 2026-01-02 电子产品 1 1299.0 U102
6 OD002 2026-01-02 电子产品 1 1299.0 U102
7 OD002 2026-01-02 电子产品 1 1299.0 U102
解读:订单号OD002的记录重复了3次(行1、6、7),按业务逻辑,同一订单号只能算1次,所以要去重。
第二步:删除重复值(drop_duplicates())
关键参数subset:指定按哪些列判断重复(比如电商订单按“订单号”判断,只要订单号重复就算重复),keep='first'保留第一次出现的行。
# 读取Excel文件
df = pd.read_excel("电商订单数据.xlsx")
df_fill = df.copy()
# 1. 按“订单号”去重,保留第一次出现的行
df_clean = df_fill.drop_duplicates(
subset=["订单号"], # 按订单号判断重复
keep="first", # 保留第一次出现的行
inplace=False # False:返回新数据框,不修改原数据;True:直接修改原数据
)
# 2. 验证去重结果
print("===== 去重后 =====")
print(f"去重前行数:{len(df_fill)}")
print(f"去重后行数:{len(df_clean)}")
print(f"去重后重复行数:{df_clean.duplicated(subset=['订单号']).sum()}")
print("\n去重后的数据:")
print(df_clean)
#########################################################################
===== 去重后 =====
去重前行数:8
去重后行数:6
去重后重复行数:0
去重后的数据:
订单号 日期 商品类别 销量(件) 销售额(元) 用户ID
0 OD001 2026-01-01 服饰 2 398.0 U101
1 OD002 2026-01-02 电子产品 1 1299.0 U102
2 OD003 2026-01-03 食品 5 NaN U103
3 OD004 2026-01-04 服饰 3 597.0 NaN
4 OD005 2026-01-05 电子产品 1000 59900.0 U105
5 OD006 2026-01-06 食品 4 88.0 U106
核心操作3:处理异常值(用箱线图+IQR,识别+过滤)
异常值是“明显不合理的数据”,比如电商销量1000件(其他都是1-5件),不处理会让“平均销量”从几十件变成几百件,误导分析。步骤是“识别→验证→处理”。

浙公网安备 33010602011771号