机器学习中的数据预处理:从入门到实践
在当今的智能时代,机器学习已经渗透到我们生活的方方面面。比如我们常用的推荐系统,它能根据我们的浏览记录精准推送喜欢的商品或视频,这背后就离不开机器学习的支撑。而一个优秀的机器学习模型,离不开高质量的数据,数据预处理正是保证数据质量的关键环节,它就像烹饪前的食材处理,直接影响着最终 “菜品” 的口感,也就是模型的性能。今天,我们就来全面学习机器学习中数据预处理的关键步骤。
一、数据预处理的重要性
数据预处理是机器学习流程中不可或缺的一步。想象一下,我们做一道菜,食材如果不新鲜、处理不干净,再好的厨艺也做不出美味佳肴。机器学习也是如此,原始数据往往存在各种问题,如缺失值、格式不统一等,不经过处理就直接用于建模,会导致模型预测不准确、性能下降。所以,做好数据预处理,是构建可靠机器学习模型的基础。
二、数据预处理的关键步骤
(一)导入需要的库
在进行数据预处理之前,我们首先要导入一些必要的库,就像做菜前要准备好厨具一样。其中,NumPy 和 Pandas 是两个每次都需要导入的重要库。
NumPy 包含了大量的数学计算函数,能帮助我们高效地进行数值运算。比如在生活中,我们计算多个商品的总价,用 NumPy 可以快速实现批量计算。
Pandas 则用于导入和管理数据集,它能像处理表格一样轻松地操作数据。
下面是导入这两个库的代码:
import numpy as np
import pandas as pd
(二)导入数据集
数据集通常是 CSV 格式,它以文本形式保存表格数据,每一行就是一条数据记录,类似于我们生活中记录信息的表格,比如学生信息表,每一行是一个学生的信息。
我们可以使用 Pandas 的 read_csv 方法读取本地 CSV 文件为一个数据帧。然后,从数据帧中制作自变量和因变量的矩阵和向量。
例如,我们有一个学生成绩数据集 “student_scores.csv”,里面包含学生的平时成绩、期末成绩和是否及格等信息。读取并划分自变量和因变量的代码如下:
dataset = pd.read_csv('student_scores.csv')
X = dataset.iloc[ : , :-1].values # 自变量矩阵,取所有行和除最后一列外的所有列
Y = dataset.iloc[ : , 2].values # 因变量向量,取所有行的第三列(假设第三列是结果)
print("X")
print(X)
print("Y")
print(Y)
(三)处理丢失数据
在实际生活中,我们收集到的数据很少是完整的,就像我们记录日常开销时,可能会忘记某天的花费,导致数据中出现 NaN 值。这些缺失的数据如果不处理,会降低机器学习模型的性能。
处理方法通常是用整列的平均值或中间值替换丢失的数据。我们可以使用 sklearn.preprocessing 库中的 SimpleImputer 类来完成这项任务。
from sklearn.impute import SimpleImputer
imputer = SimpleImputer(missing_values=np.nan, strategy="mean") # 用平均值替换NaN值
imputer = imputer.fit(X[ : , 1:3]) # 对X中第二列和第三列进行拟合
X[ : , 1:3] = imputer.transform(X[ : , 1:3]) # 转换处理缺失值
print("---------------------")
print("Step 3: Handling the missing data")
print("X")
print(X)
比如在一个学生成绩数据集中,某学生的数学成绩缺失了,我们就可以用全班同学的数学平均成绩来填补这个缺失值。
(四)解析分类数据
分类数据指的是含有标签值而不是数字值的变量,其取值范围通常是固定的。例如在问卷调查中,“是否满意” 的答案 “Yes” 和 “No”,这些不能直接用于模型的数学计算,所以需要解析成数字。
我们可以从 sklearn.preprocessing 库导入 LabelEncoder 类和 OneHotEncoder 类来实现这一功能。LabelEncoder 用于将标签值转换为数字,OneHotEncoder 用于进行独热编码,避免分类变量之间产生虚假的数值关系。
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.compose import ColumnTransformer
# 对自变量中的分类数据进行独热编码
ct = ColumnTransformer([("", OneHotEncoder(), [0])], remainder='passthrough')
X = ct.fit_transform(X)
# 对因变量中的分类数据进行编码
labelencoder_Y = LabelEncoder()
Y = labelencoder_Y.fit_transform(Y)
print("---------------------")
print("Step 4: Encoding categorical data")
print("X")
print(X)
print("Y")
print(Y)
比如对于 “国家” 这一分类变量,有 “中国”“美国”“英国” 等取值,独热编码后会将其转换为多个 0 和 1 组成的向量,更适合模型计算。
(五)拆分数据集为测试集合和训练集合
为了评估机器学习模型的性能,我们需要把数据集拆分成两个部分:一个是用来训练模型的训练集合,另一个是用来验证模型的测试集合,两者比例一般是 80:20。
我们可以导入 sklearn.model_selection 库中的 train_test_split () 方法来实现。
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2, random_state=0)
print("---------------------")
print("Step 5: Splitting the datasets into training sets and Test sets")
print("X_train")
print(X_train)
print("X_test")
print(X_test)
print("Y_train")
print(Y_train)
print("Y_test")
print(Y_test)
这就好比我们学习知识,用 80% 的练习题来学习掌握(训练集),用 20% 的题来检验学习效果(测试集)。
(六)特征缩放
大部分模型算法使用两点间的欧式距离进行计算,但不同特征在幅度、单位和范围上可能有很大差异。例如,在一个包含年龄(0-100 岁)和收入(0-100000 元)的数据集里,收入的幅度远大于年龄,在距离计算中,收入会比年龄权重更大,这会影响模型的准确性。
我们可以通过特征标准化或 Z 值归一化来解决这个问题,导入 sklearn.preprocessing 库的 StandardScaler 类即可实现。
from sklearn.preprocessing import StandardScaler
sc_X = StandardScaler()
X_train = sc_X.fit_transform(X_train) # 对训练集进行拟合和标准化
X_test = sc_X.transform(X_test) # 用训练集的参数对测试集进行标准化
print("---------------------")
print("Step 6: Feature Scaling")
print("X_train")
print(X_train)
print("X_test")
print(X_test)
为什么 fit_transform 和 transform 不一样?
- fit_transform(X_train):该操作分为两步,先通过训练集数据计算出均值、标准差等统计参数,再依据这些参数对训练集进行标准化处理,将其转化为均值为 0、标准差为 1 的分布。这一步是让模型基于训练集的分布特性进行学习,为后续建模奠定基础。
- transform(X_test):处理测试集时,不会重新计算其统计参数,而是直接复用训练集的均值和标准差来进行标准化。这样做是为了保证训练集和测试集的处理标准一致,防止测试集的信息干扰模型训练,从而更准确地评估模型对新数据的适应能力。
(七)异常值处理
异常值是指数据集中与其他数据偏离较大的值,如同班级中某同学的成绩远高于或远低于其他同学。这些异常值可能会干扰模型对数据规律的学习,导致模型预测出现偏差。
异常值检测方法
- 箱线图法:通过计算数据的四分位数,确定异常值的边界(上下限为 Q1-1.5IQR 和 Q3+1.5IQR,其中 Q1 为下四分位数,Q3 为上四分位数,IQR 为四分位距)。
- Z-score 法:若数据服从正态分布,Z-score 的绝对值大于 3 的通常被视为异常值。
异常值处理代码示例
import matplotlib.pyplot as plt
# 以训练集中的某一特征为例绘制箱线图检测异常值
plt.figure(figsize=(8, 4))
plt.boxplot(X_train[:, 1]) # 假设第二列是需要检测的特征
plt.title("特征值箱线图(检测异常值)")
plt.show()
# 计算四分位数和异常值边界
Q1 = np.percentile(X_train[:, 1], 25)
Q3 = np.percentile(X_train[:, 1], 75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
# 过滤异常值
X_train_clean = X_train[(X_train[:, 1] >= lower_bound) & (X_train[:, 1] <= upper_bound)]
Y_train_clean = Y_train[(X_train[:, 1] >= lower_bound) & (X_train[:, 1] <= upper_bound)]
比如在一个电商平台的用户消费数据中,若大部分用户月消费在 100-1000 元,而某条数据显示月消费 100000 元,这很可能是异常值,可根据实际情况删除或修正。
(八)特征选择
特征选择是从众多特征中挑选出对模型预测有重要影响的特征,减少冗余信息,提高模型的训练效率和预测精度,避免 “维度灾难”。
常用特征选择方法
- 方差选择法:删除方差过小的特征(如某特征大部分值相同,对模型影响小)。
- 相关性分析:计算特征与目标变量的相关性,选择相关性高的特征。
特征选择代码示例
# 计算特征与目标变量的相关性
corr_matrix = np.corrcoef(X_train_clean.T, Y_train_clean)
# 提取特征与目标变量的相关系数(排除最后一行目标变量自身的相关性)
feature_corr = np.abs(corr_matrix[:-1, -1])
# 选择相关性大于0.5的特征
selected_indices = np.where(feature_corr > 0.5)[0]
X_train_selected = X_train_clean[:, selected_indices]
X_test_selected = X_test[:, selected_indices]
print("选择的特征索引:", selected_indices)
print("选择后的训练集特征:")
print(X_train_selected)
例如在预测房价的模型中,房屋面积、卧室数量等特征与房价相关性较高,而房屋朝向(在某些地区)相关性较低,我们会优先选择前者作为模型输入。
(九)数据转换
部分数据可能不符合模型对数据分布的假设(如线性模型常假设数据服从正态分布),此时需要进行数据转换。常见的转换方法有对数转换、平方根转换等,用于处理偏态分布的数据。
数据转换代码示例
# 假设某特征呈现右偏分布,进行对数转换(避免值为0或负数,先加一个小常数)
X_train_transformed = X_train_selected.copy()
X_train_transformed[:, 0] = np.log(X_train_transformed[:, 0] + 1e-5)
# 查看转换前后的分布
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.hist(X_train_selected[:, 0], bins=20)
plt.title("转换前的特征分布(右偏)")
plt.subplot(1, 2, 2)
plt.hist(X_train_transformed[:, 0], bins=20)
plt.title("对数转换后的特征分布(接近正态)")
plt.show()
像居民收入数据通常呈右偏分布,通过对数转换可使其更接近正态分布,更符合模型的假设,提升模型性能。
(十)构建预处理管道
在实际项目中,数据预处理步骤较多,为了避免步骤混乱和数据泄露,我们可以使用sklearn.pipeline构建预处理管道,将所有预处理步骤整合起来,使流程更简洁高效。
预处理管道构建代码示例
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='mean')),
('scaler', StandardScaler())
])
# 构建分类型特征的预处理管道:填充缺失值+独热编码
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')), # 分类型特征用众数填充
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
# 整合所有特征的预处理管道
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
])
# 构建完整的预处理+模型管道(此处仅展示预处理部分)
pipeline = Pipeline(steps=[('preprocessor', preprocessor)])
# 对训练集进行预处理
X_train_processed = pipeline.fit_transform(X_train)
# 对测试集进行预处理
X_test_processed = pipeline.transform(X_test)
print("管道处理后的训练集:")
print(X_train_processed)
比如在一个包含多种类型特征的数据集(如既有数值型的年龄、收入,又有分类型的职业、学历)中,使用预处理管道可以自动对不同类型的特征应用相应的预处理步骤,避免人工操作的繁琐和错误。
(十一)不同数据类型的预处理差异
除了结构化数据,我们在实际应用中还会遇到文本、图像等非结构化数据,它们的预处理方法与结构化数据有所不同。
1. 文本数据预处理
文本数据需要进行分词、去除停用词、词向量转换等操作。例如:
from sklearn.feature_extraction.text import TfidfVectorizer
import nltk
from nltk.corpus import stopwords
nltk.download('stopwords')
# 示例文本数据
texts = ["I love machine learning", "Machine learning is interesting"]
# 文本预处理:去除停用词+TF-IDF转换
tfidf = TfidfVectorizer(stop_words=stopwords.words('english'))
text_features = tfidf.fit_transform(texts).toarray()
print("文本数据预处理后:")
print(text_features)
2. 图像数据预处理
图像数据通常需要进行缩放、归一化、数据增强等操作。例如:
from PIL import Image
import numpy as np
# 读取图像并缩放为28x28
image = Image.open('image.jpg').resize((28, 28))
# 转换为数组并归一化到[0,1]
image_array = np.array(image) / 255.0
print("图像数据预处理后形状:", image_array.shape)
(十二)预处理后的验证
预处理完成后,我们需要对处理结果进行验证,确保预处理步骤正确有效。可以通过以下方式验证:
- 统计指标:查看处理后数据的均值、标准差、缺失值比例等,确认符合预期。
- 可视化:绘制处理后数据的分布直方图、箱线图等,观察数据分布是否合理。
- 模型验证:使用处理后的数据训练简单模型,若模型性能明显提升,说明预处理有效。
例如,我们可以对比预处理前后模型在测试集上的准确率:
from sklearn.linear_model import LogisticRegression
# 用未预处理的数据训练模型
model_raw = LogisticRegression()
model_raw.fit(X_train, Y_train)
acc_raw = model_raw.score(X_test, Y_test)
# 用预处理后的数据训练模型
model_processed = LogisticRegression()
model_processed.fit(X_train_processed, Y_train)
acc_processed = model_processed.score(X_test_processed, Y_test)
print("未预处理模型准确率:", acc_raw)
print("预处理后模型准确率:", acc_processed)
若预处理后模型准确率显著提高,说明预处理步骤是有效的。
总结
数据预处理是机器学习项目成功的关键,它涉及数据清洗、转换、选择等多个环节。从基础的缺失值处理、特征缩放,到高级的预处理管道构建,每一步都需要结合数据特点和模型需求进行合理选择。同时,对于不同类型的数据(结构化、文本、图像等),要采用相应的预处理方法。通过构建规范的预处理流程并进行有效验证,我们能为后续的模型训练提供高质量的数据,从而提升机器学习模型的性能和可靠性。希望本文的内容能帮助读者在实际项目中更好地进行数据预处理,为构建优秀的机器学习模型奠定坚实基础。
还想看更多,来啦!!!
1,大数据比赛篇全国职业院校技能大赛-大数据比赛心得体会_全国职业职业技能比赛 大数据-CSDN博客
2,求职简历篇(超实用)大学生简历写作指南:让你的简历脱颖而出-CSDN博客
3,AIGC心得篇aigc时代,普通人需要知道的-CSDN博客
4,数据分析思维篇学习数据分析思维的共鸣-CSDN博客
5,中年危机篇“中年危机”如何转变为“中年机遇”-CSDN博客
其他需求,看主页哦!