python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python数据清洗

Python数据清洗的四大核心操作(去重/标准化/归一化/编码)实战指南

作者:黑客思维者

数据清洗就像盖房子前的地基整理,若原始数据充满重复,格式混乱,后续建模分析只会是空中楼阁,本文将从工程师视角,拆解四大核心操作的底层逻辑,结合真实业务案例,带你吃透数据清洗的底层逻辑

数据清洗就像盖房子前的地基整理——若原始数据充满重复、格式混乱、量纲不一,后续建模分析只会是“空中楼阁”。Python的Pandas、Scikit-learn库提供了成熟的工具链,但多数教程只讲“怎么用”,却回避了“为什么这么用”“实际场景中会踩什么坑”。本文将从工程师视角,拆解四大核心操作的底层逻辑,结合真实业务案例,带你吃透数据清洗的“道”与“术”。

一、四大核心操作:原理→实现→场景适配

1. 去重:剔除数据中的“冗余杂质”

(1)底层原理

去重的核心是基于哈希表的重复判断:Pandas的drop_duplicates()方法会先对数据行计算哈希值,再通过哈希比对识别重复项(默认保留首次出现的记录)。其时间复杂度为O(n),依赖Pandas对DataFrame的行哈希优化实现。

(2)实现逻辑与代码

import pandas as pd

# 构造含重复数据的业务场景数据(电商订单表)
df = pd.DataFrame({
    "订单ID": ["O1001", "O1002", "O1002", "O1003", "O1003"],
    "用户ID": ["U2023", "U2024", "U2024", "U2025", "U2025"],
    "支付金额": [199.9, 299.9, 299.9, 399.9, 399.9],
    "支付时间": ["2025-01-01 10:00", "2025-01-01 14:30", "2025-01-01 14:30", "2025-01-02 09:15", "2025-01-02 09:15"]
})

# 1. 全量去重(默认按所有列判断)
df_clean1 = df.drop_duplicates()  # 保留首次出现的记录,删除后续重复行

# 2. 按关键列去重(订单ID唯一,避免同一订单重复统计)
df_clean2 = df.drop_duplicates(subset=["订单ID"], keep="last")  # 保留最后一次支付记录(处理订单重试场景)

print(f"原始数据行数:{len(df)},全量去重后:{len(df_clean1)},按订单ID去重后:{len(df_clean2)}")

(3)场景适配边界

2. 标准化(Z-Score):让数据“站在同一基准线”

(1)底层原理

标准化的核心公式:X_std = (X - μ) / σ(μ为均值,σ为标准差),本质是将数据转换为均值=0、方差=1的标准正态分布。其设计逻辑是消除量纲影响——比如“年龄(0-100)”和“收入(0-100万)”两个特征,直接建模会导致收入的权重被过度放大。

(2)实现逻辑与代码

from sklearn.preprocessing import StandardScaler
import numpy as np

# 构造含不同量纲的特征数据(用户画像:年龄、收入、消费频次)
data = pd.DataFrame({
    "年龄": [25, 30, 35, 40, 45],
    "月收入(元)": [8000, 15000, 25000, 35000, 50000],
    "消费频次(次/月)": [5, 8, 12, 15, 20]
})

# 初始化标准化器(默认计算全局均值和标准差)
scaler = StandardScaler()
# 执行标准化(仅对数值型特征操作)
data_std = scaler.fit_transform(data[["年龄", "月收入(元)", "消费频次(次/月)"]])
data_std_df = pd.DataFrame(data_std, columns=["年龄_std", "收入_std", "频次_std"])

# 验证结果(均值≈0,方差≈1)
print("标准化后各特征均值:", np.round(data_std_df.mean(), 6))  # 输出:[0. 0. 0.]
print("标准化后各特征方差:", np.round(data_std_df.var(), 6))   # 输出:[1. 1. 1.]

(3)场景适配边界

3. 归一化(Min-Max):将数据“压缩到指定区间”

(1)底层原理

归一化的核心公式:X_norm = (X - X_min) / (X_max - X_min),本质是线性变换,将数据映射到[0,1]区间(默认)。其设计逻辑是保留数据的相对分布,适合需要固定输出范围的场景(如神经网络的输入层)。

(2)实现逻辑与代码

from sklearn.preprocessing import MinMaxScaler

# 沿用上述用户画像数据,对消费频次归一化
scaler_minmax = MinMaxScaler(feature_range=[0, 1])  # 可指定区间,如[0, 10]
data_norm = scaler_minmax.fit_transform(data[["消费频次(次/月)"]])
data["消费频次_norm"] = data_norm

print("归一化后的消费频次:", data["消费频次_norm"].tolist())  # 输出:[0. , 0.375, 0.7, 0.95, 1. ]

(3)标准化vs归一化:核心差异与选型

对比维度标准化(Z-Score)归一化(Min-Max)
核心特点均值=0,方差=1映射到固定区间
抗异常值能力较强(受σ缓冲)较弱(受X_max/X_min影响)
适用模型线性模型、距离模型神经网络、需要固定范围的场景
数据要求需近似正态分布无分布要求

4. 编码:让模型“读懂分类数据”

(1)底层原理

机器模型只能处理数值型数据,编码的核心是将分类特征(字符串/离散值)映射为数值。不同编码方式的设计差异,本质是解决“如何表达分类间的关系”(如是否有序、是否独立)。

(2)主流编码方式实现与场景

# 构造分类特征数据(电商商品表:类别、品牌、评分等级)
df_category = pd.DataFrame({
    "商品类别": ["电子产品", "服装", "食品", "电子产品", "服装"],
    "品牌": ["华为", "耐克", "海底捞", "苹果", "阿迪达斯"],
    "评分等级": ["高", "中", "高", "中", "低"]  # 有序分类
})

# 1. 独热编码(One-Hot):适用于无序分类(如商品类别、品牌)
df_onehot = pd.get_dummies(df_category, columns=["商品类别", "品牌"])

# 2. 标签编码(LabelEncoder):适用于有序分类(如评分等级)
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
df_category["评分等级_encoded"] = le.fit_transform(df_category["评分等级"])  # 高=2,中=1,低=0

# 3. 有序编码(OrdinalEncoder):显式指定有序关系(推荐)
from sklearn.preprocessing import OrdinalEncoder
oe = OrdinalEncoder(categories=[["低", "中", "高"]])
df_category["评分等级_ordinal"] = oe.fit_transform(df_category[["评分等级"]])  # 低=0,中=1,高=2

print("独热编码后数据形状:", df_onehot.shape)  # 输出:(5, 8),新增6个编码列
print("有序编码结果:", df_category["评分等级_ordinal"].tolist())  # 输出:[2.0, 1.0, 2.0, 1.0, 0.0]

(3)场景适配边界

二、真实工程案例:电商用户行为数据清洗全流程

1. 案例背景

一个电商平台的用户行为数据集(100万行),包含用户ID、商品ID、浏览时长、消费金额、商品类别、支付状态等字段,需清洗后用于“用户购买意向预测模型”训练。

2. 业务痛点

3. 清洗流程与代码实现

# 1. 数据加载与探索
df_behavior = pd.read_csv("user_behavior.csv")
print(f"原始数据形状:{df_behavior.shape}")
print(f"缺失值统计:\n{df_behavior.isnull().sum()}")
print(f"异常值统计(消费金额):{len(df_behavior[(df_behavior['消费金额']  (df_behavior['消费金额'] > 100000)])}")

# 2. 去重(按用户ID+商品ID去重,保留最后一次浏览记录)
df_behavior = df_behavior.drop_duplicates(subset=["用户ID", "商品ID"], keep="last")

# 3. 异常值处理(删除无效消费金额记录)
df_behavior = df_behavior[(df_behavior["消费金额"] > 0) & (df_behavior["消费金额"] 000)]

# 4. 标准化(对浏览时长、消费金额标准化)
scaler = StandardScaler()
df_behavior[["浏览时长_std", "消费金额_std"]] = scaler.fit_transform(df_behavior[["浏览时长", "消费金额"]])

# 5. 编码(对商品类别独热编码,支付状态标签编码)
df_behavior = pd.get_dummies(df_behavior, columns=["商品类别"])
le_pay = LabelEncoder()
df_behavior["支付状态_encoded"] = le_pay.fit_transform(df_behavior["支付状态"])

# 6. 结果验证
print(f"清洗后数据形状:{df_behavior.shape}")
print(f"标准化后消费金额均值:{df_behavior['消费金额_std'].mean():.6f},方差:{df_behavior['消费金额_std'].var():.6f}")

4. 上线效果反馈

三、5个高频坑点与Trouble Shooting

坑点1:去重时忽略“业务主键”,导致有效数据丢失

坑点2:标准化时包含异常值,导致结果失真

代码示例:

# 先剔除异常值(3σ法则)
def remove_outliers(df, col):
    mu = df[col].mean()
    sigma = df[col].std()
    return df[(df[col] >= mu - 3*sigma) & (df[col] sigma)]

df_behavior["消费金额"] = remove_outliers(df_behavior, "消费金额")

坑点3:对无序分类使用LabelEncoder,误导模型

坑点4:归一化时受极值影响,数据分布被扭曲

代码示例:

# 对数变换处理极值
df_behavior["收入_log"] = np.log1p(df_behavior["月收入(元)"])
# 再归一化
scaler_minmax = MinMaxScaler()
df_behavior["收入_log_norm"] = scaler_minmax.fit_transform(df_behavior[["收入_log"]])

坑点5:编码时引发“维度爆炸”

四、进阶思考:数据清洗的演进与未来方向

1. 传统方法vs现代方案:效率与效果的平衡

2. 未来优化方向:自动化与智能化

五、总结与应用建议

到此这篇关于Python数据清洗的四大核心操作(去重/标准化/归一化/编码)实战指南的文章就介绍到这了,更多相关Python数据清洗内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文