Python数据清洗与特征工程:打造高质量数据集的实战指南10
各位Python编程爱好者和数据科学探索者们,大家好!我是您的知识博主。今天,我们将深入探讨Python编程与实战系列中的一个核心环节——数据预处理。在机器学习和数据分析领域,流传着这样一句话:“数据是金,但很多时候它是‘矿石’,需要提炼才能闪光。” 还有一句广为人知的格言:“Garbage In, Garbage Out”(垃圾进,垃圾出)。这两句话都深刻地揭示了数据预处理的重要性。许多数据科学家和机器学习工程师将80%的时间投入到数据的收集、清洗和转换上,这足以说明其在整个项目生命周期中的关键地位。
本篇文章,我们将以“实战”为导向,使用Python中最强大的数据处理库——Pandas,结合NumPy和Scikit-learn,带大家走过数据清洗(Data Cleaning)和特征工程(Feature Engineering)的完整流程,帮助您将原始、混乱的数据转化为模型可用、甚至能提升模型性能的高质量特征。
第一部分:理解数据预处理的重要性
在开始实战之前,我们必须明确数据预处理为什么如此重要。原始数据往往存在各种问题:
缺失值(Missing Values): 数据采集不完整,导致某些字段为空。
重复值(Duplicate Values): 相同的数据行或关键信息重复录入,干扰分析。
异常值(Outliers): 远离数据主体的大或小的值,可能是录入错误,也可能代表特殊情况,需要谨慎处理。
数据类型不一致(Inconsistent Data Types): 数字被存储为字符串,日期格式五花八门。
数据噪声(Noise): 随机错误或不相关的信息。
不平衡数据(Imbalanced Data): 某些类别的样本数量远多于其他类别,影响分类模型训练。
非结构化数据: 文本、图片等需要转换为数值形式。
这些问题会严重影响模型的训练效果和泛化能力。而特征工程则是更进一步,通过对现有特征进行转换、组合或创建新特征,来提高模型的预测精度和解释性。一个好的特征往往能胜过复杂的模型。
第二部分:Python数据清洗实战 (使用Pandas)
我们将以一个虚拟的数据集(例如:一份用户消费记录或房屋销售数据)为例,展示如何使用Pandas进行数据清洗。
1. 环境准备与数据加载
首先,确保您安装了Pandas和NumPy。
import pandas as pd
import numpy as np
# 假设我们有一个名为''的原始数据集
try:
df = pd.read_csv('')
except FileNotFoundError:
print(" not found. Creating a dummy DataFrame for demonstration.")
data = {
'CustomerID': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 11, 12, 13, 14, 15],
'Age': [25, 30, , 45, 22, 35, 28, 50, 60, 25, 30, , 40, 33, 29, 27],
'Gender': ['Male', 'Female', 'Male', 'Female', 'Other', 'Male', 'Female', 'Male', 'Female', 'Male', 'Female', 'Male', 'Female', 'Male', 'Female', 'Male'],
'City': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', 'New York'],
'PurchaseAmount': [100.50, 200.75, 50.00, 150.25, 300.00, , 75.50, 120.00, 400.00, 80.00, 200.75, 180.00, 60.00, 250.00, 90.00, 110.00],
'PurchaseDate': ['2023-01-01', '2023-01-05', '2023-01-10', '2023-01-15', '2023-01-20', '2023-01-25', '2023-02-01', '2023-02-05', '2023-02-10', '2023-02-15', '2023-01-05', '2023-02-20', '2023-02-25', '2023-03-01', '2023-03-05', '2023-03-10'],
'ProductCategory': ['Electronics', 'Books', 'Home', 'Electronics', 'Books', 'Home', 'Electronics', 'Books', 'Home', 'Electronics', 'Books', 'Home', 'Electronics', 'Books', 'Home', 'Electronics'],
'DiscountApplied': [True, False, False, True, False, False, True, False, True, False, False, True, False, False, True, False],
'Comments': ['Good product', 'Fast delivery', 'Ok', 'Great experience', '', 'Nice item', 'Satisfied', 'Excellent', 'Very happy', 'No comment', 'Fast delivery', 'Happy with purchase', 'Good quality', 'Worth it', 'Love it', 'Recommend']
}
df = (data)
# 引入一些不一致性
[2, 'Gender'] = 'male' # 小写
[5, 'City'] = 'new york' # 小写
[11, 'PurchaseAmount'] = '180.00' # 字符串数字
[13, 'PurchaseDate'] = '2023/03/01' # 不同日期格式
2. 数据概览与初步探索
加载数据后,第一步是了解它的基本情况。
print("数据前5行:", ())
print("数据基本信息:")
()
print("数值型数据统计描述:")
print(())
print("数据形状:", )
通过`()`我们可以快速发现数据类型问题(如PurchaseAmount被识别为object),以及哪些列存在非空值,从而初步判断缺失值情况。
3. 处理缺失值
缺失值是数据清洗中最常见的问题之一。
print("各列缺失值数量:", ().sum())
# 策略1: 删除含有缺失值的行 (适用于缺失值较少且对整体数据影响不大的情况)
df_cleaned_drop = ()
print("删除缺失值后的数据形状:", )
# 策略2: 填充缺失值
# 数值型数据:可以使用均值(mean)、中位数(median)或众数(mode)填充
# 以Age为例,使用中位数填充(对异常值更鲁棒)
df['Age'].fillna(df['Age'].median(), inplace=True)
# 以PurchaseAmount为例,先转换为数值类型,再填充
# 发现有字符串,先转换为数值,无法转换的变为NaN
df['PurchaseAmount'] = pd.to_numeric(df['PurchaseAmount'], errors='coerce')
df['PurchaseAmount'].fillna(df['PurchaseAmount'].mean(), inplace=True)
# 类别型数据:可以使用众数或固定值填充
# 假设ProductCategory也有缺失,用众数填充
# df['ProductCategory'].fillna(df['ProductCategory'].mode()[0], inplace=True) # 本例中ProductCategory无缺失
print("填充缺失值后的缺失值数量:", ().sum())
4. 处理重复值
重复数据会夸大某些特征的重要性。
print("重复行数量:", ().sum())
# 删除所有重复行
df.drop_duplicates(inplace=True)
print("删除重复行后的数据形状:", )
# 如果只关心某些列的重复(例如,根据CustomerID和PurchaseDate判断是否是重复购买记录)
# df.drop_duplicates(subset=['CustomerID', 'PurchaseDate'], inplace=True)
5. 数据类型转换
确保每列的数据类型都正确,这对后续的分析和模型训练至关重要。
print("原始数据类型:", )
# 将PurchaseAmount转换为浮点数 (已在缺失值处理中完成)
# df['PurchaseAmount'] = pd.to_numeric(df['PurchaseAmount'], errors='coerce')
# 将PurchaseDate转换为日期时间类型
df['PurchaseDate'] = pd.to_datetime(df['PurchaseDate'], errors='coerce', format='mixed') # format='mixed' 自动推断多种格式
# 检查转换后的数据类型
print("转换数据类型后的数据类型:", )
6. 处理不一致数据与异常值
不一致数据(例如:大小写不统一):
print("原始Gender值:", df['Gender'].unique())
df['Gender'] = df['Gender'].().replace('other', 'unknown') # 统一大小写并将'Other'处理为'Unknown'
print("处理后的Gender值:", df['Gender'].unique())
print("原始City值:", df['City'].unique())
df['City'] = df['City'].() # 将城市名统一为首字母大写
print("处理后的City值:", df['City'].unique())
异常值(Outliers): 异常值处理是一个复杂的话题,通常需要结合业务理解。常见的检测方法有Z-score、IQR(四分位距)等。处理方法包括删除、替换(如用均值/中位数)、或将其视为一个特殊类别。
# 简单示例:假设PurchaseAmount大于350被认为是异常高值,我们用350来上限封顶
# 这是一种常见的处理方法,称为“Winsorization”或“Capping”
upper_bound = df['PurchaseAmount'].quantile(0.99) # 取99分位数作为上限
df['PurchaseAmount'] = (df['PurchaseAmount'] > upper_bound, upper_bound, df['PurchaseAmount'])
print(f"PurchaseAmount 异常值(大于 {upper_bound:.2f})已进行上限封顶处理。")
print(df['PurchaseAmount'].describe())
第三部分:Python特征工程实战
特征工程是数据预处理的“艺术”部分,它通过对现有特征的转换和组合,创建出更具预测能力的特征。
1. 类别特征编码 (Categorical Feature Encoding)
机器学习模型通常不能直接处理文本类别特征,需要将其转换为数值。
One-Hot编码: 适用于没有序关系的类别特征(如City, Gender)。
# 对'Gender', 'City', 'ProductCategory'进行One-Hot编码
df = pd.get_dummies(df, columns=['Gender', 'City', 'ProductCategory'], drop_first=True, dtype=int)
print("One-Hot编码后的数据前5行:", ())
print("One-Hot编码后的数据形状:", )
Label Encoding: 适用于有序关系的类别特征(例如:S-M-L-XL),或类别数量非常多,One-Hot编码会导致维度灾难的情况。通常Scikit-learn的`LabelEncoder`是一个好选择。
from import LabelEncoder
# 假设ProductCategory是Clothing下的'Small', 'Medium', 'Large'
# le = LabelEncoder()
# df['Size_Encoded'] = le.fit_transform(df['Size'])
2. 数值特征转换
标准化 (Standardization) 与 归一化 (Normalization):
标准化 (Standardization / Z-score Normalization): 将特征转换为均值为0,标准差为1的正态分布。适用于大多数机器学习模型,特别是对特征尺度敏感的模型(如SVM,K-Means)。
from import StandardScaler
scaler = StandardScaler()
df['Age_Scaled'] = scaler.fit_transform(df[['Age']])
df['PurchaseAmount_Scaled'] = scaler.fit_transform(df[['PurchaseAmount']])
print("Age和PurchaseAmount标准化后:", df[['Age_Scaled', 'PurchaseAmount_Scaled']].head())
归一化 (Normalization / Min-Max Scaling): 将特征缩放到固定范围(通常是0到1)。适用于需要将数据限定在特定区间的场景(如神经网络)。
from import MinMaxScaler
minmax_scaler = MinMaxScaler()
# df['Age_Normalized'] = minmax_scaler.fit_transform(df[['Age']])
对数变换 (Log Transformation): 适用于高度偏斜的数值特征,可以使其更接近正态分布,减少极端值的影响。
# 假设PurchaseAmount偏斜,进行对数变换
df['PurchaseAmount_Log'] = np.log1p(df['PurchaseAmount']) # log1p是log(1+x),处理0值更稳定
print("PurchaseAmount对数变换后:", df[['PurchaseAmount', 'PurchaseAmount_Log']].head())
3. 时间序列特征提取
从日期时间特征中提取有用的信息。
# 确保PurchaseDate是datetime类型
# df['PurchaseDate'] = pd.to_datetime(df['PurchaseDate']) # 已经在清洗阶段完成
df['PurchaseYear'] = df['PurchaseDate'].
df['PurchaseMonth'] = df['PurchaseDate'].
df['PurchaseDay'] = df['PurchaseDate'].
df['PurchaseDayOfWeek'] = df['PurchaseDate']. # 0=星期一, 6=星期日
df['IsWeekend'] = df['PurchaseDayOfWeek'].apply(lambda x: 1 if x >= 5 else 0) # 判断是否周末
print("时间特征提取后:", df[['PurchaseDate', 'PurchaseYear', 'PurchaseMonth', 'PurchaseDay', 'PurchaseDayOfWeek', 'IsWeekend']].head())
4. 创建组合特征 (Interaction Features)
通过组合现有特征来捕捉它们之间的相互作用。
# 例如:用户每年的平均消费金额(需要更复杂的分组聚合)
# df['AvgAnnualPurchase'] = (['CustomerID', 'PurchaseYear'])['PurchaseAmount'].transform('mean')
# 简单示例:TotalAmountPerCustomer (每个客户的总消费)
customer_total_purchase = ('CustomerID')['PurchaseAmount'].transform('sum')
df['TotalPurchasePerCustomer'] = customer_total_purchase
print("组合特征 (TotalPurchasePerCustomer) 后:", df[['CustomerID', 'PurchaseAmount', 'TotalPurchasePerCustomer']].head())
5. 特征分箱 (Binning/Discretization)
将连续数值特征划分为离散的区间或箱,可以处理非线性关系,减少噪声。
# 将年龄特征分箱:年轻人,中年人,老年人
bins = [0, 18, 35, 55, 100]
labels = ['Young', 'Adult', 'Middle-Aged', 'Senior']
df['Age_Category'] = (df['Age'], bins=bins, labels=labels, right=False)
print("年龄特征分箱后:", df[['Age', 'Age_Category']].head())
# 对分箱后的类别再进行One-Hot编码
df = pd.get_dummies(df, columns=['Age_Category'], drop_first=True, dtype=int)
第四部分:实战中的最佳实践与思考
数据预处理并非一蹴而就,它是一个迭代、探索性的过程。以下是一些最佳实践和思考:
数据备份: 始终保留原始数据集的副本,以便回溯和比较。
可视化: 在每个清洗和特征工程步骤前后,使用Seaborn、Matplotlib等库对数据进行可视化,直观地检查效果和发现潜在问题。
领域知识: 结合业务领域的专业知识进行特征工程往往能产生更有效的特征。例如,在金融风控中,可以计算“逾期天数”;在电商中,可以创建“用户活跃天数”。
特征选择: 创建了大量特征后,需要进行特征选择(如:过滤法、包裹法、嵌入法)来去除冗余或不重要的特征,以提高模型效率和避免过拟合。
自动化与管道化 (Pipeline): 在生产环境中,应将数据预处理流程封装成可重复使用的函数或Scikit-learn的Pipeline,确保数据处理的一致性和效率。
from import Pipeline
from import SimpleImputer
from import StandardScaler, OneHotEncoder
from import ColumnTransformer
# 创建数值型特征的处理流程
numeric_features = ['Age', 'PurchaseAmount']
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')), # 缺失值填充
('scaler', StandardScaler()) # 标准化
])
# 创建类别型特征的处理流程
categorical_features = ['Gender', 'City', 'ProductCategory'] # 假设这里还有未编码的原始列
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')), # 缺失值填充
('onehot', OneHotEncoder(handle_unknown='ignore')) # One-Hot编码
])
# 将不同类型的特征处理流程整合
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
])
# 最终你可以将预处理器整合到模型训练管道中
# model = Pipeline(steps=[('preprocessor', preprocessor),
# ('classifier', LogisticRegression())])
# (X_train, y_train)
结语
数据清洗与特征工程是数据科学中不可或缺的环节。通过Python及其强大的库(尤其是Pandas),我们可以高效、灵活地对数据进行各种操作,将“脏乱差”的原始数据转化为“清晰、有价值”的模型输入。这不仅是提升模型性能的关键,更是培养数据洞察力、理解数据本质的重要途径。希望通过本篇文章的实战指导,您能更好地掌握数据预处理的精髓,在您的数据科学之路上迈出更坚实的一步!下次我们将可能探讨更高级的特征工程技巧或模型选择与评估。敬请期待!
2026-03-02
JavaScript “onmove“ 迷思:深入理解DOM移动事件与最佳实践
https://jb123.cn/javascript/72745.html
从入门到精通:Perl编程语言的系统学习路径与实战指南
https://jb123.cn/perl/72744.html
Python实现凯撒密码:从入门到实践的加密解密之旅
https://jb123.cn/python/72743.html
Python编程软件大揭秘:从入门到专业,总有一款适合你!
https://jb123.cn/python/72742.html
JavaScript eval()深度解析:从强大到危险,你真的了解它吗?
https://jb123.cn/javascript/72741.html
热门文章
Python 编程解密:从谜团到清晰
https://jb123.cn/python/24279.html
Python编程深圳:初学者入门指南
https://jb123.cn/python/24225.html
Python 编程终端:让开发者畅所欲为的指令中心
https://jb123.cn/python/22225.html
Python 编程专业指南:踏上编程之路的全面指南
https://jb123.cn/python/20671.html
Python 面向对象编程学习宝典,PDF 免费下载
https://jb123.cn/python/3929.html