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件),不处理会让“平均销量”从几十件变成几百件,误导分析。步骤是“识别→验证→处理”。

 

 

 

  

 

 

posted @ 2026-01-19 14:08  梦徒  阅读(1)  评论(0)    收藏  举报