机器学习中的数据预处理步骤
数据预处理是机器学习工作流程中至关重要的一环,它能够显著提高模型的性能和准确性。以下是数据预处理的主要步骤及相关的scikit-learn函数和使用场景:
1. 数据加载与探索
在开始处理数据之前,首先需要加载数据并了解其基本情况。
常用函数:
pandas.read_csv()
/pandas.read_excel()
- 读取数据文件pandas.DataFrame.describe()
- 获取数据统计摘要pandas.DataFrame.info()
- 查看数据类型和缺失值pandas.DataFrame.head()
- 查看前几行数据
实例:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 加载数据
df = pd.read_csv('dataset.csv')
# 查看数据信息
print(df.info())
print(df.describe())
# 查看前几行数据
print(df.head())
# 数据可视化
plt.figure(figsize=(10, 6))
sns.heatmap(df.corr(), annot=True, cmap='coolwarm')
plt.title('特征相关性矩阵')
plt.show()
2. 处理缺失值
缺失值可能会影响模型训练效果,需要通过填充或删除来处理。
常用函数:
sklearn.impute.SimpleImputer
- 用于替换缺失值pandas.DataFrame.dropna()
- 删除包含缺失值的行或列
使用场景:
- 当缺失值较少时,可以考虑删除包含缺失值的行
- 对于连续型变量,可以用均值、中位数或众数填充
- 对于分类变量,可以用众数填充
实例:
from sklearn.impute import SimpleImputer
# 使用均值填充数值型特征的缺失值
numerical_imputer = SimpleImputer(strategy='mean')
df_numerical = df.select_dtypes(include=['int64', 'float64'])
df[df_numerical.columns] = numerical_imputer.fit_transform(df_numerical)
# 使用众数填充分类特征的缺失值
categorical_imputer = SimpleImputer(strategy='most_frequent')
df_categorical = df.select_dtypes(include=['object'])
df[df_categorical.columns] = categorical_imputer.fit_transform(df_categorical)
3. 处理异常值/离群点
异常值会影响统计分析和模型训练,需要识别并处理。
常用函数:
sklearn.ensemble.IsolationForest
- 异常检测scipy.stats.zscore
- 计算Z分数
使用场景:
- 当数据集较大且异常点很明显时,可以考虑删除
- 也可以考虑将异常值截断到某个合理范围
- 对于高维数据,可以使用隔离森林等算法检测异常值
实例:
import numpy as np
from scipy import stats
# 使用Z分数检测并处理异常值
z_scores = stats.zscore(df['feature'])
abs_z_scores = np.abs(z_scores)
filtered_entries = (abs_z_scores < 3) # 保留Z分数绝对值小于3的数据点
df_no_outliers = df[filtered_entries]
# 或者使用IQR方法检测并处理异常值
Q1 = df['feature'].quantile(0.25)
Q3 = df['feature'].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
df_no_outliers = df[(df['feature'] >= lower_bound) & (df['feature'] <= upper_bound)]
4. 特征编码
将分类特征转换为数值形式,以便模型可以处理。
常用函数:
sklearn.preprocessing.LabelEncoder
- 将类别标签编码为0到n_classes-1sklearn.preprocessing.OneHotEncoder
- 将分类特征转换为独热编码sklearn.preprocessing.OrdinalEncoder
- 用于有序分类特征的编码sklearn.preprocessing.TargetEncoder
- 用目标变量的均值替换分类变量
使用场景:
LabelEncoder
适用于目标变量的编码OneHotEncoder
适用于没有顺序关系的分类特征OrdinalEncoder
适用于有顺序关系的分类特征TargetEncoder
适合处理高基数分类特征
实例:
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
# 对目标变量进行标签编码
label_encoder = LabelEncoder()
df['target_encoded'] = label_encoder.fit_transform(df['target'])
# 对分类特征进行独热编码
categorical_features = ['feature1', 'feature2']
one_hot_encoder = OneHotEncoder(sparse_output=False, drop='first')
encoded_features = one_hot_encoder.fit_transform(df[categorical_features])
encoded_df = pd.DataFrame(encoded_features,
columns=one_hot_encoder.get_feature_names_out(categorical_features))
df = pd.concat([df.drop(categorical_features, axis=1), encoded_df], axis=1)
5. 特征缩放/标准化
调整特征的尺度,使特征具有可比性,这对于许多算法非常重要。
常用函数:
sklearn.preprocessing.StandardScaler
- 标准化,使数据均值为0,标准差为1sklearn.preprocessing.MinMaxScaler
- 将数据缩放到特定范围(默认为[0,1])sklearn.preprocessing.RobustScaler
- 使用中位数和四分位数,对异常值不敏感sklearn.preprocessing.Normalizer
- 将样本缩放到单位范数
使用场景:
StandardScaler
适用于正态分布数据MinMaxScaler
适用于希望特征在固定范围内的情况RobustScaler
适用于存在异常值的数据Normalizer
适用于需要考虑样本向量方向而非幅值的情况
实例:
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
# 标准化
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df[['feature1', 'feature2', 'feature3']])
# MinMax缩放到[0,1]区间
min_max_scaler = MinMaxScaler()
df_min_max_scaled = min_max_scaler.fit_transform(df[['feature1', 'feature2', 'feature3']])
# 使用RobustScaler处理有异常值的数据
robust_scaler = RobustScaler()
df_robust_scaled = robust_scaler.fit_transform(df[['feature1', 'feature2', 'feature3']])
6. 特征选择
选择最相关或最重要的特征,减少维度,提高模型性能。
常用函数:
sklearn.feature_selection.SelectKBest
- 选择K个最佳特征sklearn.feature_selection.RFE
- 递归特征消除sklearn.feature_selection.SelectFromModel
- 基于模型的特征选择
使用场景:
SelectKBest
适用于基于统计测试选择特征RFE
适用于通过递归减少特征数量SelectFromModel
适用于基于树模型等提取特征重要性
实例:
from sklearn.feature_selection import SelectKBest, f_classif, RFE
from sklearn.ensemble import RandomForestClassifier
# 使用SelectKBest选择最佳的3个特征
selector = SelectKBest(score_func=f_classif, k=3)
X_new = selector.fit_transform(X, y)
selected_features = X.columns[selector.get_support()]
# 使用随机森林和RFE进行特征选择
rf = RandomForestClassifier()
rfe = RFE(estimator=rf, n_features_to_select=5)
X_rfe = rfe.fit_transform(X, y)
selected_features_rfe = X.columns[rfe.support_]
7. 特征工程
创建新特征或转换现有特征,以提高模型性能。
常用函数:
sklearn.preprocessing.PolynomialFeatures
- 创建多项式特征sklearn.preprocessing.FunctionTransformer
- 应用自定义函数变换sklearn.decomposition.PCA
- 主成分分析降维
使用场景:
PolynomialFeatures
适用于捕捉非线性关系FunctionTransformer
适用于应用自定义变换PCA
适用于降维和处理多重共线性
实例:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.decomposition import PCA
# 创建多项式特征
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X)
# 使用PCA降维
pca = PCA(n_components=5)
X_pca = pca.fit_transform(X)
print(f"解释方差比例: {pca.explained_variance_ratio_}")
8. 数据分割
将数据集分为训练集和测试集,以评估模型性能。
常用函数:
sklearn.model_selection.train_test_split
- 随机分割数据集sklearn.model_selection.KFold
- K折交叉验证
使用场景:
train_test_split
适用于简单的训练/测试分割KFold
适用于进行交叉验证
实例:
from sklearn.model_selection import train_test_split, KFold
# 简单的训练/测试分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# K折交叉验证
kf = KFold(n_splits=5, shuffle=True, random_state=42)
for train_index, test_index in kf.split(X):
X_train, X_test = X.iloc[train_index], X.iloc[test_index]
y_train, y_test = y.iloc[train_index], y.iloc[test_index]
# 训练和评估模型
9. 类别不平衡处理
处理训练集中类别分布不均的情况。
常用函数:
sklearn.utils.class_weight.compute_class_weight
- 计算类别权重imblearn.over_sampling.SMOTE
- 合成少数类过采样技术imblearn.under_sampling.RandomUnderSampler
- 随机欠采样
使用场景:
- 当类别严重不平衡时
- 当少数类样本较少或稀有事件检测
实例:
from imblearn.over_sampling import SMOTE
from sklearn.utils.class_weight import compute_class_weight
# 使用SMOTE过采样
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y)
# 计算类别权重
class_weights = compute_class_weight(class_weight='balanced', classes=np.unique(y), y=y)
class_weight_dict = dict(zip(np.unique(y), class_weights))
# 在模型中使用类别权重
model = RandomForestClassifier(class_weight=class_weight_dict)
完整的数据预处理实例
下面是一个完整的数据预处理流程示例,整合了上述步骤:
import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
# 1. 加载数据
df = pd.read_csv('你的数据.csv')
print("数据基本信息:")
print(df.info())
print("\n数据预览:")
print(df.head())
# 2. 分离特征和目标变量
X = df.drop('target', axis=1)
y = df['target']
# 3. 识别数值和分类特征
numerical_features = X.select_dtypes(include=['int64', 'float64']).columns.tolist()
categorical_features = X.select_dtypes(include=['object']).columns.tolist()
# 4. 创建数据预处理管道
# 数值特征处理:填充缺失值 + 标准化
numerical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
# 分类特征处理:填充缺失值 + 独热编码
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
# 组合所有预处理步骤
preprocessor = ColumnTransformer(
transformers=[
('num', numerical_transformer, numerical_features),
('cat', categorical_transformer, categorical_features)
])
# 5. 创建完整的模型管道
model_pipeline = Pipeline(steps=[
('preprocessor', preprocessor),
('classifier', RandomForestClassifier(random_state=42))
])
# 6. 分割数据为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 7. 训练模型
model_pipeline.fit(X_train, y_train)
# 8. 评估模型
y_pred = model_pipeline.predict(X_test)
print("\n模型评估:")
print(classification_report(y_test, y_pred))
# 9. 特征重要性分析(如果适用)
if hasattr(model_pipeline.named_steps['classifier'], 'feature_importances_'):
# 获取处理后的特征名称
feature_names = []
# 获取数值特征名称
if numerical_features:
feature_names.extend(numerical_features)
# 获取独热编码后的分类特征名称
if categorical_features:
ohe = preprocessor.named_transformers_['cat'].named_steps['onehot']
feature_names.extend(ohe.get_feature_names_out(categorical_features))
# 获取特征重要性
importances = model_pipeline.named_steps['classifier'].feature_importances_
# 创建特征重要性DataFrame并排序
feature_importance_df = pd.DataFrame({
'Feature': feature_names,
'Importance': importances
}).sort_values(by='Importance', ascending=False)
print("\n特征重要性:")
print(feature_importance_df.head(10)) # 显示前10个重要特征
以上是使用scikit-learn进行数据预处理的完整流程,包括数据加载、缺失值处理、特征编码、特征缩放、特征工程和模型训练与评估。这个流程适用于大多数机器学习任务,可以根据具体数据集和问题进行适当调整。