当前位置: 首页 > ds >正文

Pandas-数据清洗与处理

Pandas-数据清洗与处理

    • 一、数据清洗的核心目标
    • 二、缺失值处理
      • 1. 缺失值检测
      • 2. 缺失值处理策略
        • (1)删除法
        • (2)填充法
    • 三、异常值识别与处理
      • 1. 异常值检测方法
        • (1)统计法
        • (2)业务规则法
      • 2. 异常值处理策略
    • 四、重复数据处理
      • 1. 重复数据检测
      • 2. 重复数据处理
    • 五、数据格式转换与标准化
      • 1. 日期时间格式转换
      • 2. 文本数据清洗
      • 3. 数据类型转换
    • 六、应用实例:完整数据清洗流程

数据清洗与处理往往占据最多的时间,现实世界中的数据很少是完美的——它们可能包含缺失值、异常值、重复记录,或是格式混乱、命名不规范的字段。Pandas作为Python数据处理的瑞士军刀,提供了强大而灵活的工具来应对这些问题。

一、数据清洗的核心目标

数据清洗的最终目的是提升数据质量,为后续分析和建模奠定基础。具体来说,需要实现以下目标:

  • 完整性:处理缺失值,确保关键信息不缺失
  • 一致性:统一数据格式、命名规范和取值标准
  • 准确性:识别并修正异常值、错误数据
  • 唯一性:去除重复记录,避免分析结果偏差
  • 可用性:将数据转换为便于分析的结构(如日期类型、分类编码)

围绕这些目标,Pandas提供了从简单到复杂的一系列处理函数,掌握它们的组合使用是高效清洗数据的关键。

二、缺失值处理

缺失值是数据清洗中最常见的问题,Pandas通过isnull()dropna()fillna()等函数形成完整的处理链条。

1. 缺失值检测

首先需要定位缺失值的位置和比例:

import pandas as pd
import numpy as np# 读取示例数据
df = pd.read_csv('messy_data.csv')# 检测每列缺失值数量及比例
missing_count = df.isnull().sum()
missing_ratio = (missing_count / len(df)).round(3)
missing_df = pd.DataFrame({'缺失值数量': missing_count,'缺失比例': missing_ratio
})
print("缺失值统计:")
print(missing_df[missing_df['缺失值数量'] > 0])  # 只显示有缺失的列

2. 缺失值处理策略

根据缺失比例和字段重要性,选择不同的处理方式:

(1)删除法

适用于缺失比例极高(如超过80%)或对分析无影响的字段,或缺失行数量极少的情况:

# 删除缺失比例超过50%的列
threshold = len(df) * 0.5
df = df.dropna(thresh=threshold, axis=1)# 删除关键字段(如用户ID)缺失的行
df = df.dropna(subset=['user_id', 'order_date'])
(2)填充法

对于重要字段,需根据字段类型选择合理的填充值:

# 数值型字段:用中位数填充(抗异常值能力强于均值)
df['amount'] = df['amount'].fillna(df['amount'].median())# 分类型字段:用众数或特殊标记(如"未知")填充
df['category'] = df['category'].fillna(df['category'].mode()[0])
df['city'] = df['city'].fillna('未知城市')# 时间型字段:用前后值填充(适用于时间序列数据)
df['login_time'] = df['login_time'].fillna(method='ffill')  # 向前填充
df['logout_time'] = df['logout_time'].fillna(method='bfill')  # 向后填充# 分组填充:按类别分组后,用组内均值填充(更精准)
df['score'] = df.groupby('class')['score'].transform(lambda x: x.fillna(x.mean())
)

三、异常值识别与处理

异常值(离群点)会扭曲统计结果和模型训练,需结合业务逻辑识别并处理。

1. 异常值检测方法

(1)统计法

适用于数值型字段,通过四分位距(IQR)或标准差判断:

def detect_outliers_iqr(df, col):"""用IQR法检测异常值"""q1 = df[col].quantile(0.25)q3 = df[col].quantile(0.75)iqr = q3 - q1lower_bound = q1 - 1.5 * iqrupper_bound = q3 + 1.5 * iqrreturn (df[col] < lower_bound) | (df[col] > upper_bound)# 检测"金额"字段的异常值
df['is_amount_outlier'] = detect_outliers_iqr(df, 'amount')
print(f"异常值比例:{df['is_amount_outlier'].mean():.2%}")
(2)业务规则法

基于领域知识判断,如订单金额不能为负、年龄不能超过150岁:

# 检测金额为负的异常值
df['is_invalid_amount'] = df['amount'] < 0# 检测年龄不合理的记录
df['is_invalid_age'] = (df['age'] < 0) | (df['age'] > 150)

2. 异常值处理策略

# 1. 修正明显错误(如金额为负可能是符号错误)
df.loc[df['amount'] < 0, 'amount'] = df.loc[df['amount'] < 0, 'amount'].abs()# 2. 截断法(将异常值限制在合理范围内)
q1, q3 = df['amount'].quantile([0.25, 0.75])
df['amount'] = df['amount'].clip(lower=q1 - 1.5 * (q3 - q1), upper=q3 + 1.5 * (q3 - q1))# 3. 标记法(保留异常值但标记,供后续分析)
df['age'] = df['age'].mask(df['age'] > 120, np.nan)  # 用NaN标记异常年龄,后续填充

四、重复数据处理

重复数据可能导致分析结果偏误(如重复计算同一订单),需检测并去重。

1. 重复数据检测

# 检测完全重复的行
duplicate_rows = df.duplicated().sum()
print(f"完全重复的行数:{duplicate_rows}")# 检测关键字段组合重复(如同一用户同一时间的重复记录)
duplicate_combo = df.duplicated(subset=['user_id', 'login_time'], keep=False).sum()
print(f"用户-时间组合重复的记录数:{duplicate_combo}")# 查看重复样本
if duplicate_rows > 0:print("重复样本示例:")print(df[df.duplicated(keep=False)].head())

2. 重复数据处理

# 保留第一次出现的记录,删除后续重复行
df = df.drop_duplicates(keep='first')# 对关键字段组合去重,并保留金额最大的记录
df = df.sort_values('amount', ascending=False)  # 按金额降序排列
df = df.drop_duplicates(subset=['user_id', 'product_id'], keep='first')

五、数据格式转换与标准化

原始数据常存在格式混乱问题(如日期格式不统一、文本大小写混用),需标准化处理。

1. 日期时间格式转换

日期字段若以字符串形式存储,需转换为datetime类型才能进行时间运算:

# 转换日期字符串为datetime类型(支持多种格式自动识别)
df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce')
# errors='coerce'将无效格式转为NaT(缺失日期)# 提取日期中的年、月、周等信息
df['order_year'] = df['order_date'].dt.year
df['order_month'] = df['order_date'].dt.month
df['is_weekend'] = df['order_date'].dt.dayofweek.isin([5, 6])  # 判断是否周末

2. 文本数据清洗

处理文本字段中的大小写、空格、特殊字符等问题:

# 去除字符串前后空格
df['product_name'] = df['product_name'].str.strip()# 统一为小写(适用于不区分大小写的场景)
df['category'] = df['category'].str.lower()# 替换特殊字符(如将"手机_"和"手机("统一为"手机")
df['category'] = df['category'].str.replace(r'[_\(\)]', '', regex=True)# 提取文本中的数字(如从"价格:99元"中提取99)
df['price'] = df['price_text'].str.extract(r'(\d+)').astype(float)

3. 数据类型转换

优化数据类型以减少内存占用,或满足分析需求:

# 将字符串ID转换为分类类型(适用于高基数但重复值多的字段)
df['user_id'] = df['user_id'].astype('category')# 将数值型字符串转换为数值类型(如"100.5"→100.5)
df['amount'] = pd.to_numeric(df['amount_str'], errors='coerce')# 将布尔值转换为0/1(便于某些模型处理)
df['is_vip'] = df['is_vip'].astype(int)

六、应用实例:完整数据清洗流程

def clean_data(df):"""完整的数据清洗函数"""print(f"原始数据形状:{df.shape}")# 1. 缺失值处理print("\n=== 处理缺失值 ===")# 删除无意义的高缺失列df = df.drop(columns=['unused_col1', 'unused_col2'])# 填充数值列和分类型列num_cols = df.select_dtypes(include=['int64', 'float64']).columnsfor col in num_cols:df[col] = df[col].fillna(df[col].median())cat_cols = df.select_dtypes(include=['object', 'category']).columnsfor col in cat_cols:df[col] = df[col].fillna(df[col].mode()[0] if not df[col].mode().empty else '未知')# 2. 异常值处理print("\n=== 处理异常值 ===")df['amount'] = df['amount'].clip(lower=0)  # 金额不能为负df['age'] = df['age'].mask((df['age'] < 0) | (df['age'] > 120), df['age'].median())# 3. 重复数据处理print("\n=== 处理重复数据 ===")df = df.drop_duplicates(subset=['order_id'], keep='first')# 4. 格式转换print("\n=== 格式转换 ===")df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce')df['product_name'] = df['product_name'].str.strip().str.lower()print(f"清洗后数据形状:{df.shape}")return df# 执行清洗流程
cleaned_df = clean_data(df)

总结:数据清洗的核心原则

  1. 理解业务:数据清洗的前提是理解字段含义和业务逻辑(如“年龄为负”在业务中一定是错误)。
  2. 保留痕迹:重要的修改(如异常值替换、缺失值填充)应记录在日志中,确保可追溯。
  3. 分步验证:每完成一步清洗,都需验证结果(如检查填充后是否还有缺失值)。
  4. 自动化复用:将清洗步骤封装为函数,便于在新数据上重复使用,保证处理逻辑一致。

That’s all, thanks for reading~~
觉得有用就点个赞、收进收藏夹吧!关注我,获取更多干货~

http://www.xdnf.cn/news/15495.html

相关文章:

  • 构建可落地的企业AI Agent,背后隐藏着怎样的技术密码?
  • redis汇总笔记
  • 什么时候需要用到 multiprocessing?
  • 基于 CentOS 7 的 LVS+DR+Web+NFS 旅游攻略分享平台部署
  • 【RA-Eco-RA6E2-64PIN-V1.0 开发板】ADC 电压的 LabVIEW 数据采集
  • 【读书笔记】《Effective Modern C++》第六章 Lambda Expressions
  • Windows 常用命令
  • vue防内存泄漏和性能优化浅解
  • 如何自动化处理TXT日志,提升工作效率新方式
  • RabbitMQ队列的选择
  • 03.Python 字符串中的空白字符处理
  • Springboot实现一个接口加密
  • 华为交换机 undo negotiation auto功能(华为交换机端口接光纤两端起不来)
  • 【Complete Search】-基础完全搜索-Basic Complete Search
  • JAVA 项目工程化实践
  • fatal: active `post-checkout` hook found during `git clone`
  • v-for中key值的作用:为什么我总被要求加这个‘没用的‘属性?
  • 大小为 K 且平均值大于等于阈值的子数组数目
  • “找到一个或多个多重定义的符号“(LNK2005 或 LNK1169)
  • 006_测试评估与安全实践
  • 深入理解 LangChain:AI 应用开发的全新范式
  • 面试150 填充每个节点的下一个右侧节点指针Ⅱ
  • 第一个Flink 程序 WordCount,词频统计(批处理)
  • ReAct论文解读(1)—什么是ReAct?
  • AI大模型计数能力的深度剖析:从理论缺陷到技术改进
  • Java行为型模式---观察者模式
  • macOS - Chrome 关闭自动更新
  • c语言初阶 结构体
  • 基于Flink的实时开发平台-Dinky
  • v-show和v-if的区别