使用Python进行数据清洗:从理论到实践
在数据分析和机器学习项目中,数据清洗(Data Cleaning)是整个流程中最关键的一步。原始数据往往包含缺失值、异常值、重复数据等问题,这些问题如果不加以处理,将严重影响模型的效果和分析结果的准确性。
本文将介绍使用 Python 进行数据清洗的基本流程,并通过一个完整的代码示例来演示如何对真实数据集进行清理和预处理。
什么是数据清洗?
数据清洗是指发现并修正数据集中错误、不一致、缺失或无效的数据的过程。其主要目标是提高数据质量,为后续的数据分析或建模提供准确、可靠的数据基础。
常见的数据清洗任务包括:
处理缺失值删除或修正异常值去除重复记录标准化/归一化数据格式数据类型转换为什么需要数据清洗?
提高模型准确性:脏数据会导致模型训练出偏差。避免误导性:分析基于错误数据可能导致错误决策。提升系统性能:减少冗余数据可以加快处理速度。增强数据一致性:统一格式便于后续分析与整合。工具准备
我们将使用以下 Python 库进行数据清洗:
pandas
:用于数据操作和结构化数据处理numpy
:用于数值计算seaborn
和 matplotlib
:用于数据可视化scikit-learn
:可选,用于数据标准化等操作安装方式(如未安装):
pip install pandas numpy seaborn matplotlib scikit-learn
实战案例:二手房价格数据清洗
我们以一个模拟的“二手房交易数据”为例,展示完整的清洗过程。
4.1 加载数据
首先加载数据:
import pandas as pd# 加载数据df = pd.read_csv("house_prices.csv")# 显示前几行print(df.head())
输出可能如下:
id | area | price | rooms | floor | build_year | address |
---|---|---|---|---|---|---|
101 | 89 | 560000 | 3 | 5/6 | 2005 | 北京市朝阳区 |
102 | NaN | -1 | 2 | high | 1998 | 上海浦东新区 |
103 | 76 | 480000 | 2 | 3/6 | 2010 | 广州市天河区 |
104 | 90 | 600000 | 3 | low | 2007 | 深圳南山区 |
可以看到,数据存在以下几个问题:
缺失值(如area列中的NaN)异常值(price为负数)非结构化的floor字段(如high、low)地址字段格式不统一4.2 处理缺失值
我们可以使用 isnull()
方法查看各列缺失情况:
print(df.isnull().sum())
假设输出如下:
id 0area 1price 0rooms 0floor 0build_year 0address 0
说明只有 area
列有缺失值。我们选择用平均值填充:
df['area'].fillna(df['area'].mean(), inplace=True)
4.3 处理异常值
观察 price
列是否有不合理值(如负值):
print(df[df['price'] < 0])
如果有异常值,可以用条件筛选并删除:
df = df[df['price'] > 0]
也可以使用 IQR 法识别并处理异常值:
Q1 = df['price'].quantile(0.25)Q3 = df['price'].quantile(0.75)IQR = Q3 - Q1lower_bound = Q1 - 1.5 * IQRupper_bound = Q3 + 1.5 * IQRdf = df[(df['price'] >= lower_bound) & (df['price'] <= upper_bound)]
4.4 统一格式:楼层信息
floor
字段中混杂了中文描述和分数形式(如 "5/6" 或 "high")。我们可以将其拆分为两个字段:当前楼层和总楼层。
def parse_floor(floor): if '/' in str(floor): current, total = map(int, floor.split('/')) return {'current_floor': current, 'total_floors': total} elif floor == 'high': return {'current_floor': 5, 'total_floors': 10} elif floor == 'mid': return {'current_floor': 3, 'total_floors': 6} elif floor == 'low': return {'current_floor': 1, 'total_floors': 5} else: return {'current_floor': None, 'total_floors': None}# 应用函数floor_info = df['floor'].apply(parse_floor).apply(pd.Series)df = pd.concat([df, floor_info], axis=1)df.drop('floor', axis=1, inplace=True)print(df.head())
4.5 地址字段标准化
地址字段内容不统一,我们可以提取城市作为新特征:
def extract_city(address): if '北京' in address: return '北京' elif '上海' in address: return '上海' elif '广州' in address: return '广州' elif '深圳' in address: return '深圳' else: return '其他'df['city'] = df['address'].apply(extract_city)df.drop('address', axis=1, inplace=True)print(df.head())
4.6 数据类型转换与标准化
确保所有数值型字段为浮点或整型:
df['area'] = df['area'].astype(float)df['price'] = df['price'].astype(int)df['rooms'] = df['rooms'].astype(int)
如果需要,还可以对面积和价格进行标准化:
from sklearn.preprocessing import StandardScalerscaler = StandardScaler()df[['area_scaled', 'price_scaled']] = scaler.fit_transform(df[['area', 'price']])
保存清洗后的数据
最后,将清洗后的数据保存为新的 CSV 文件:
df.to_csv("cleaned_house_prices.csv", index=False)
总结
本文介绍了使用 Python 对数据进行清洗的完整流程,包括:
处理缺失值清除异常值格式统一与结构化地址字段标准化数据类型转换与标准化这些步骤不仅适用于房价数据,也适用于各种结构化数据的清洗任务。
拓展建议
自动化清洗流程:使用函数封装清洗步骤,方便复用。日志记录:在清洗过程中记录每一步处理了多少条数据。数据质量报告:生成缺失率、唯一值数量等统计报表。集成进流水线:结合 Scikit-Learn 的 Pipeline 实现端到端的数据处理流程。附录:完整代码清单
import pandas as pdimport numpy as npfrom sklearn.preprocessing import StandardScaler# 加载数据df = pd.read_csv("house_prices.csv")# 查看缺失值print(df.isnull().sum())# 填充缺失值df['area'].fillna(df['area'].mean(), inplace=True)# 删除异常价格df = df[df['price'] > 0]# 使用 IQR 方法去除异常值Q1 = df['price'].quantile(0.25)Q3 = df['price'].quantile(0.75)IQR = Q3 - Q1lower_bound = Q1 - 1.5 * IQRupper_bound = Q3 + 1.5 * IQRdf = df[(df['price'] >= lower_bound) & (df['price'] <= upper_bound)]# 解析楼层字段def parse_floor(floor): if '/' in str(floor): current, total = map(int, floor.split('/')) return {'current_floor': current, 'total_floors': total} elif floor == 'high': return {'current_floor': 5, 'total_floors': 10} elif floor == 'mid': return {'current_floor': 3, 'total_floors': 6} elif floor == 'low': return {'current_floor': 1, 'total_floors': 5} else: return {'current_floor': None, 'total_floors': None}floor_info = df['floor'].apply(parse_floor).apply(pd.Series)df = pd.concat([df, floor_info], axis=1)df.drop('floor', axis=1, inplace=True)# 提取城市信息def extract_city(address): if '北京' in address: return '北京' elif '上海' in address: return '上海' elif '广州' in address: return '广州' elif '深圳' in address: return '深圳' else: return '其他'df['city'] = df['address'].apply(extract_city)df.drop('address', axis=1, inplace=True)# 类型转换df['area'] = df['area'].astype(float)df['price'] = df['price'].astype(int)df['rooms'] = df['rooms'].astype(int)# 标准化scaler = StandardScaler()df[['area_scaled', 'price_scaled']] = scaler.fit_transform(df[['area', 'price']])# 保存数据df.to_csv("cleaned_house_prices.csv", index=False)
如果你正在构建一个数据驱动的产品或进行数据分析工作,数据清洗是一个不可或缺的环节。希望这篇文章能帮助你更好地掌握这一技能。