
图片来源:编辑 | Midjourney
在机器学习项目中,要实现最佳的模型性能,就需要关注训练过程中的各个环节。但在专注于模型训练的技术细节之前,首先要定义问题、理解上下文并详细分析数据集。
一旦你对问题和数据有了扎实的掌握,就可以着手实施能够帮助你构建强大而高效模型的策略。在此,我们概述了五个对训练机器学习模型至关重要的实用技巧。
让我们开始吧。
1. 高效地预处理你的数据
数据预处理是机器学习管道中最关键的步骤之一。正确预处理的数据可以显著提高模型的性能和泛化能力。以下是一些关键的预处理步骤:
- 处理缺失值:使用均值/众数填补等技术,或使用 K-近邻(KNN)填补等更高级的方法。
- 对特征进行归一化或标准化:如果使用对特征缩放敏感的算法,请对特征进行缩放。
- 对分类变量进行编码:使用独热编码或标签编码等技术将分类变量转换为数值。
- 拆分为训练集和测试集:在应用任何预处理步骤之前,将数据拆分为训练集和测试集,以避免数据泄露。
以下代码片段展示了一个示例数据预处理管道。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import pandas as pd 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 # 从 CSV 文件读取数据 data = pd.read_csv('your_data.csv') # 指定目标变量的列名 target_column = 'target' # 拆分为特征和目标 X = data.drop(target_column, axis=1) y = data[target_column] # 拆分为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=10) # 识别数值和分类列 numeric_features = X.select_dtypes(include=['int64', 'float64']).columns.tolist() categorical_features = X.select_dtypes(include=['object', 'category']).columns.tolist() # 定义数值特征的预处理步骤 numeric_transformer = Pipeline(steps=[ ('imputer', SimpleImputer(strategy='mean')), ('scaler', StandardScaler()) ]) # 定义分类特征的预处理步骤 categorical_transformer = Pipeline(steps=[ ('encoder', OneHotEncoder(drop='first')) ]) # 组合预处理步骤 preprocessor = ColumnTransformer( transformers=[ ('num', numeric_transformer, numeric_features), ('cat', categorical_transformer, categorical_features) ] ) # 应用预处理到训练数据 X_train_processed = preprocessor.fit_transform(X_train) # 应用预处理到测试数据 X_test_processed = preprocessor.transform(X_test) |
为数值特征和分类特征定义了预处理步骤:数值特征用均值进行填补并使用 StandardScaler 进行缩放,而分类特征则进行独热编码。这些预处理步骤使用 ColumnTransformer 进行组合,并应用于训练集和测试集,同时避免数据泄露。
2. 专注于特征工程
特征工程是一个系统化的过程,旨在修改现有特征并创建新特征以提高模型性能。有效的特征工程可以显著提升机器学习模型的性能。以下是一些关键技术:
创建交互特征
交互特征捕捉了不同变量之间的关系。这些特征可以提供单个特征无法揭示的额外洞察。
假设你有“price”和“qty_sold”作为特征。交互特征可以是这两个变量的乘积,表示产品的总销售额。
1 2 |
# 创建交互特征 data['price_qty_interaction'] = data['price'] * data['qty_sold'] |
从日期和时间特征中提取信息
日期和时间数据可以分解为有意义的组成部分,如年、月、日和星期几。这些组成部分可以揭示数据中的时间模式。
假设你有一个“date”特征。你可以从该特征中提取各种组成部分——年、月和星期几——如下所示。
1 2 3 4 5 |
# 提取日期特征 data['date'] = pd.to_datetime(['2020-01-01', '2020-02-01', '2020-03-01', '2020-04-01']) data['year'] = data['date'].dt.year data['month'] = data['date'].dt.month data['day_of_week'] = data['date'].dt.dayofweek |
分箱
分箱是将连续特征转换为离散箱的过程。这有助于减少异常值的影响并创建更具代表性的特征。
假设你有一个“income”特征。你可以创建箱来将收入水平划分为低、中、高,如下所示。
1 2 |
# 对连续特征进行分箱 data['income_bin'] = pd.cut(data['income'], bins=3, labels=['Low', 'Medium', 'High']) |
通过专注于特征工程,你可以创建更有信息量的特征,帮助模型更好地理解数据,从而提高性能和泛化能力。阅读 机器学习中有效特征工程的技巧 以获取有关特征工程的实用技巧。
3. 处理类别不平衡
类别不平衡是真实世界数据集中一个常见的问题,其中目标变量的类别表示不均匀。在此类不平衡数据集上训练的模型的性能指标并不可靠。
处理类别不平衡对于确保模型在所有类别上都能表现良好是必要的。以下是一些技术。
重采样技术
重采样技术涉及修改数据集以平衡类别分布。主要有两种方法:
- 过采样:通过复制或创建合成样本来增加少数类别的实例数量。合成少数类别过采样技术(SMOTE)是生成合成样本的一种流行方法。
- 欠采样:通过随机删除一些多数类别的实例来减少其数量。
下面是一个使用 SMOTE 对少数类别进行过采样的示例。
1 2 3 4 5 6 7 8 9 10 11 |
from imblearn.over_sampling import SMOTE from sklearn.model_selection import train_test_split X = data.drop('target', axis=1) y = data['target'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=10) # 应用 SMOTE smote = SMOTE(random_state=10) X_resampled, y_resampled = smote.fit_resample(X_train, y_train) |
调整类别权重
调整机器学习算法中的类别权重有助于惩罚对少数类别的错误分类,使模型对少数类别更敏感。
考虑以下示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import pandas as pd from sklearn.model_selection import train_test_split # 从 CSV 文件读取数据 data = pd.read_csv('your_data.csv') # 指定目标变量的列名 target_column = 'target' # 拆分为特征和目标 X = data.drop(target_column, axis=1) y = data[target_column] # 拆分为训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=10) |
你可以计算类别权重,为少数类别分配更高的权重——与类别频率成反比——然后像这样在实例化分类器时使用这些权重。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score, classification_report from sklearn.utils.class_weight import compute_class_weight # 计算类别权重 classes = np.unique(y_train) class_weights = compute_class_weight(class_weight='balanced', classes=classes, y=y_train) class_weights_dict = dict(zip(classes, class_weights)) print(f"类别权重:{class_weights_dict}") model = RandomForestClassifier(class_weight=class_weights_dict, random_state=10) model.fit(X_train, y_train) # 在测试集上进行预测 y_pred = model.predict(X_test) # 评估模型 print(f'准确率:{accuracy_score(y_test, y_pred):.2f}') print(classification_report(y_test, y_pred)) |
通过使用这些技术,你可以有效地处理类别不平衡,确保你的模型在所有类别上都能表现良好。要了解有关处理类别不平衡的更多信息,请阅读 处理机器学习中不平衡数据的 5 种有效方法。
4. 使用交叉验证和超参数调整
交叉验证和超参数调整是选择最佳模型和避免过拟合的关键技术。它们有助于确保模型在未见过的数据上表现良好,而不会出现性能下降。
交叉验证
使用单一的训练-测试拆分会导致模型方差过高,并且更容易受到(比预期更多的)最终进入训练集和测试集的特定样本的影响。
交叉验证是一种通过将数据分成多个子集或折叠,并在这些折叠上训练和测试模型来评估模型性能的技术。
最常见的方法是 K 折交叉验证,即将数据分成 K 个子集,每次训练和评估模型 K 次。每次使用一个折作为测试集,其余 (K-1) 个折作为训练集。
我们重用之前的样板代码。
1 2 3 4 5 6 7 8 9 10 11 12 |
import pandas as pd from sklearn.model_selection import train_test_split # 从 CSV 文件读取数据 data = pd.read_csv('your_data.csv') # 指定目标变量的列名 target_column = 'target' # 拆分为特征和目标 X = data.drop(target_column, axis=1) y = data[target_column] |
以下是如何使用 K 折交叉验证来评估 RandomForestClassifier。
1 2 3 4 5 6 7 8 9 10 11 12 |
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import cross_val_score # 初始化模型 model = RandomForestClassifier(random_state=10) # 执行 5 折交叉验证 cv_scores = cross_val_score(model, X, y, cv=5) # 打印交叉验证分数 print(f'交叉验证分数:{cv_scores}') print(f'平均 CV 分数:{cv_scores.mean():.2f}') |
超参数调优
超参数调整涉及为模型找到最佳超参数。两种常见技术是:
- 网格搜索:它涉及对选定的参数网格进行穷举搜索。在大多数情况下,这可能非常昂贵。
- 随机搜索:它从指定的分布中随机采样参数值。
要了解有关超参数调整的更多信息,请阅读。超参数调整:GridSearchCV 和 RandomizedSearchCV 详解。
以下是如何使用网格搜索查找最佳超参数的示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import GridSearchCV # 定义参数网格 param_grid = { 'n_estimators': [50, 100, 200], 'max_depth': [None, 10, 20, 30], 'min_samples_split': [2, 5, 10] } # 初始化模型 model = RandomForestClassifier(random_state=10) # 执行具有 5 折交叉验证的网格搜索 grid_search = GridSearchCV(estimator=model, param_grid=param_grid, cv=5, scoring='accuracy') grid_search.fit(X, y) print(f'最佳参数:{grid_search.best_params_}') print(f'最佳交叉验证分数:{grid_search.best_score_:.2f}') |
交叉验证可确保模型在未见过的数据上表现最佳,而超参数调整则有助于优化模型参数以获得更好的性能。
5. 选择最佳机器学习模型
虽然你可以使用超参数调整来优化选定的模型,但选择合适的模型同样重要。评估多个模型并选择最适合你的数据集和你试图解决的问题的模型至关重要。
交叉验证可提供对模型在未见过的数据上性能的可靠估计。因此,通过交叉验证分数比较不同的模型有助于识别在你的数据上表现最佳的模型。
以下是如何使用交叉验证来比较逻辑回归和随机森林分类器(省略了启动代码)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import cross_val_score # 拆分为特征和目标 X = data.drop('target', axis=1) y = data['target'] # 定义要比较的模型 models = { 'Logistic Regression': LogisticRegression(random_state=10), 'Random Forest': RandomForestClassifier(random_state=10), } # 使用交叉验证比较模型 for name, model in models.items(): cv_scores = cross_val_score(model, X, y, cv=5, scoring='accuracy') print(f'{name} CV 分数:{cv_scores.mean():.2f}') |
你还可以使用集成方法,将多个模型结合起来以提高性能。它们在减少过拟合方面特别有效,从而产生更强大的模型。你可能会发现 为你的数据选择正确的机器学习模型的技巧 对了解模型选择有所帮助。
总结
希望你学到了一些在训练机器学习模型时需要记住的有用技巧。让我们回顾一下:
- 根据需要处理缺失值、缩放特征和编码分类变量。在进行任何预处理之前,尽早将数据拆分为训练集和测试集。
- 创建交互特征、提取有用的日期/时间特征,并使用分箱和其他技术创建更具代表性的特征。
- 使用重采样技术和调整类别权重来处理类别不平衡。
- 实现 K 折交叉验证和网格搜索或随机搜索等超参数优化技术,以进行稳健的模型评估。
- 使用交叉验证分数比较模型,并考虑使用集成方法来提高性能。
祝模型构建愉快!
博客中的新技术很棒。