Sklearn RFE、管道和交叉验证
Sklearn RFE, pipeline and cross validation
我正在尝试弄清楚如何使用 RFE 解决回归问题,并且我正在阅读一些教程。
我找到了一个关于如何使用 RFECV 自动 select 理想数量特征的例子,它是这样的:
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.feature_selection import RFECV
rfecv = RFECV(estimator=RandomForestClassifier(random_state=101), step=1, cv=StratifiedKFold(10), scoring='accuracy')
rfecv.fit(X, target)
print(np.where(rfecv.support_ == False)[0])
我觉得这很简单。
然而,我正在检查如何使用 RFE 对象做同样的事情,但为了包括交叉验证,我只找到了涉及使用管道的解决方案,例如:
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# create pipeline
rfe = RFE(estimator=DecisionTreeRegressor(), n_features_to_select=5)
model = DecisionTreeRegressor()
pipeline = Pipeline(steps=[('s',rfe),('m',model)])
# evaluate model
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
# report performance
print(f'MAE: {mean(n_scores):.3f}')
我不确定这里到底发生了什么。
pipeline用于排队RFE算法和第二个DecisionTreeRegressor(模型)。
如果我没记错的话,这个想法是对于交叉验证中的每次迭代,执行 RFE,所需数量的最佳特征是 selected,然后第二个模型是 运行只使用那些功能。
但是 how/when RFE 是否将有关哪些功能已 selected 的信息传递给 DecisionTreeRegressor?它甚至发生了吗,或者代码是否缺少这一部分?
嗯,首先,让我们指出 RFECV 和 RFE 在您的脚本中做两个独立的工作:前者选择最佳数量的特征,而后者选择最重要的五个特征(或者, 5 个特征的最佳组合,考虑到它们对 DecisionTreeRegressor 的重要性)。
回到你的问题:“RFE是什么时候将选择了哪些特征的信息传递给决策树的?”值得注意的是,RFE 并没有明确告诉 Decision Tree 选择了哪些特征。简单地说,它以一个矩阵作为输入(训练集),并根据 n_features_to_select=N
参数将其转换为 N 列的矩阵。
该矩阵(即转换后的训练集)与目标变量一起作为输入传递给决策树,目标变量 return 是一个可用于预测未见实例的拟合模型。
让我们深入研究一个分类示例:
""" Import dependencies and load data """
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import RFE
from sklearn.metrics import precision_score
from sklearn.tree import DecisionTreeClassifier
X, y = load_breast_cancer(return_X_y=True)
rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=2)
我们现在已经加载了 breast_cancer 数据集并实例化了一个 RFE 对象(我使用了 DecisionTreeClassifier,但也可以使用其他算法)。
要了解如何在管道中处理训练数据,让我们从一个手动示例开始,该示例说明如果在其“基本步骤”中分解管道将如何工作:
from sklearn.model_selection import train_test_split
def test_and_train(X, y, random_state):
# For simplicity, let's use 80%-20% splitting
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=random_state)
# Fit and transform the training data by applying Recursive Feature Elimination
X_train_transformed = rfe.fit_transform(X_train, y_train)
# Transform the testing data to select the same features
X_test_transformed = rfe.transform(X_test)
print(X_train[0:3])
print(X_train_transformed[0:3])
print(X_test_transformed[0:3])
# Train on the transformed trained data
fitted_model = DecisionTreeClassifier().fit(X_train_transformed, y_train)
# Predict on the transformed testing data
y_pred = fitted_model.predict(X_test_transformed)
print('True labels: ', y_test)
print('Predicted labels:', y_pred)
return y_test, y_pred
precisions = list() # to store the precision scores (can be replaced by any other evaluation measure)
y_test, y_pred = test_and_train(X, y, 42)
precisions.append(precision_score(y_test, y_pred))
y_test, y_pred = test_and_train(X, y, 84)
precisions.append(precision_score(y_test, y_pred))
y_test, y_pred = test_and_train(X, y, 168)
precisions.append(precision_score(y_test, y_pred))
print('Average precision:', np.mean(precisions))
"""
Average precision: 0.92
"""
在上面的脚本中,我们创建了一个函数,给定一个数据集 X
和一个目标变量 y
- 按照 80%-20% 的拆分规则创建训练集和测试集。
- 使用 RFE 转换它们(即,选择最好的 2 个特征,如前一个代码片段中指定的那样)。在 RFE 上调用
fit_transform
时,它会运行递归特征消除,并且 它会在其对象状态 中保存有关所选特征的信息。要知道哪些是选定的功能,请调用 rfe.support_
。
注意:在测试集上只执行transform,所以rfe.support_
中的特征用来过滤掉其他特征测试集。
- 适合模型和 return 元组(y_test、y_pred)。
y_test
和 y_pred
可用于分析模型的性能,例如其精度。
精度保存在数组中,重复3次。
最后,我们打印平均精度。
我们模拟了一个交叉验证过程,通过将原始数据在各自的训练和测试集中拆分 3 次,拟合模型,计算并平均其在三个折叠中的性能(即精度)。
使用 RepeatedKFold 验证可以简化此过程:
from sklearn.model_selection import RepeatedKFold
precisions = list()
rkf = RepeatedKFold(n_splits=2, n_repeats=3, random_state=1)
for train_index, test_index in rkf.split(X, y):
# print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
X_train_transformed = rfe.fit_transform(X_train, y_train)
X_test_transformed = rfe.transform(X_test)
fitted_model = DecisionTreeClassifier().fit(X_train_transformed, y_train)
y_pred = fitted_model.predict(X_test_transformed)
precisions.append(precision_score(y_test, y_pred))
print('Average precision:', np.mean(precisions))
"""
Average precision: 0.93
"""
甚至更进一步的管道:
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score
rkf = RepeatedKFold(n_splits=2, n_repeats=3, random_state=1)
pipeline = Pipeline(steps=[('s',rfe),('m',DecisionTreeClassifier())])
precisions = cross_val_score(pipeline, X, y, scoring='precision', cv=rkf)
print('Average precision:', np.mean(precisions))
"""
Average precision: 0.93
"""
综上所述,当原始数据传递给Pipeline时,后者:
- 在训练和测试数据中拆分它;
- 对训练数据调用
RFE.fit_transform()
;
- 对测试数据应用
RFE.transform()
,使其包含相同的特征;
- 对训练数据调用
estimator.fit()
以拟合(即训练)模型;
- 调用
estimator.predict()
测试数据进行预测。
- 将预测值与实际值进行比较,并在内部保存性能结果(您传递给
scoring
参数的结果)。
- 对交叉验证过程中的每个拆分重复步骤 1-6
在程序结束时,有人可以访问性能结果并在各个折叠中取平均值。
我正在尝试弄清楚如何使用 RFE 解决回归问题,并且我正在阅读一些教程。
我找到了一个关于如何使用 RFECV 自动 select 理想数量特征的例子,它是这样的:
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.feature_selection import RFECV
rfecv = RFECV(estimator=RandomForestClassifier(random_state=101), step=1, cv=StratifiedKFold(10), scoring='accuracy')
rfecv.fit(X, target)
print(np.where(rfecv.support_ == False)[0])
我觉得这很简单。
然而,我正在检查如何使用 RFE 对象做同样的事情,但为了包括交叉验证,我只找到了涉及使用管道的解决方案,例如:
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# create pipeline
rfe = RFE(estimator=DecisionTreeRegressor(), n_features_to_select=5)
model = DecisionTreeRegressor()
pipeline = Pipeline(steps=[('s',rfe),('m',model)])
# evaluate model
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
# report performance
print(f'MAE: {mean(n_scores):.3f}')
我不确定这里到底发生了什么。 pipeline用于排队RFE算法和第二个DecisionTreeRegressor(模型)。 如果我没记错的话,这个想法是对于交叉验证中的每次迭代,执行 RFE,所需数量的最佳特征是 selected,然后第二个模型是 运行只使用那些功能。 但是 how/when RFE 是否将有关哪些功能已 selected 的信息传递给 DecisionTreeRegressor?它甚至发生了吗,或者代码是否缺少这一部分?
嗯,首先,让我们指出 RFECV 和 RFE 在您的脚本中做两个独立的工作:前者选择最佳数量的特征,而后者选择最重要的五个特征(或者, 5 个特征的最佳组合,考虑到它们对 DecisionTreeRegressor 的重要性)。
回到你的问题:“RFE是什么时候将选择了哪些特征的信息传递给决策树的?”值得注意的是,RFE 并没有明确告诉 Decision Tree 选择了哪些特征。简单地说,它以一个矩阵作为输入(训练集),并根据 n_features_to_select=N
参数将其转换为 N 列的矩阵。
该矩阵(即转换后的训练集)与目标变量一起作为输入传递给决策树,目标变量 return 是一个可用于预测未见实例的拟合模型。
让我们深入研究一个分类示例:
""" Import dependencies and load data """
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import RFE
from sklearn.metrics import precision_score
from sklearn.tree import DecisionTreeClassifier
X, y = load_breast_cancer(return_X_y=True)
rfe = RFE(estimator=DecisionTreeClassifier(), n_features_to_select=2)
我们现在已经加载了 breast_cancer 数据集并实例化了一个 RFE 对象(我使用了 DecisionTreeClassifier,但也可以使用其他算法)。
要了解如何在管道中处理训练数据,让我们从一个手动示例开始,该示例说明如果在其“基本步骤”中分解管道将如何工作:
from sklearn.model_selection import train_test_split
def test_and_train(X, y, random_state):
# For simplicity, let's use 80%-20% splitting
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=random_state)
# Fit and transform the training data by applying Recursive Feature Elimination
X_train_transformed = rfe.fit_transform(X_train, y_train)
# Transform the testing data to select the same features
X_test_transformed = rfe.transform(X_test)
print(X_train[0:3])
print(X_train_transformed[0:3])
print(X_test_transformed[0:3])
# Train on the transformed trained data
fitted_model = DecisionTreeClassifier().fit(X_train_transformed, y_train)
# Predict on the transformed testing data
y_pred = fitted_model.predict(X_test_transformed)
print('True labels: ', y_test)
print('Predicted labels:', y_pred)
return y_test, y_pred
precisions = list() # to store the precision scores (can be replaced by any other evaluation measure)
y_test, y_pred = test_and_train(X, y, 42)
precisions.append(precision_score(y_test, y_pred))
y_test, y_pred = test_and_train(X, y, 84)
precisions.append(precision_score(y_test, y_pred))
y_test, y_pred = test_and_train(X, y, 168)
precisions.append(precision_score(y_test, y_pred))
print('Average precision:', np.mean(precisions))
"""
Average precision: 0.92
"""
在上面的脚本中,我们创建了一个函数,给定一个数据集 X
和一个目标变量 y
- 按照 80%-20% 的拆分规则创建训练集和测试集。
- 使用 RFE 转换它们(即,选择最好的 2 个特征,如前一个代码片段中指定的那样)。在 RFE 上调用
fit_transform
时,它会运行递归特征消除,并且 它会在其对象状态 中保存有关所选特征的信息。要知道哪些是选定的功能,请调用rfe.support_
。 注意:在测试集上只执行transform,所以rfe.support_
中的特征用来过滤掉其他特征测试集。 - 适合模型和 return 元组(y_test、y_pred)。
y_test
和 y_pred
可用于分析模型的性能,例如其精度。
精度保存在数组中,重复3次。
最后,我们打印平均精度。
我们模拟了一个交叉验证过程,通过将原始数据在各自的训练和测试集中拆分 3 次,拟合模型,计算并平均其在三个折叠中的性能(即精度)。 使用 RepeatedKFold 验证可以简化此过程:
from sklearn.model_selection import RepeatedKFold
precisions = list()
rkf = RepeatedKFold(n_splits=2, n_repeats=3, random_state=1)
for train_index, test_index in rkf.split(X, y):
# print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
X_train_transformed = rfe.fit_transform(X_train, y_train)
X_test_transformed = rfe.transform(X_test)
fitted_model = DecisionTreeClassifier().fit(X_train_transformed, y_train)
y_pred = fitted_model.predict(X_test_transformed)
precisions.append(precision_score(y_test, y_pred))
print('Average precision:', np.mean(precisions))
"""
Average precision: 0.93
"""
甚至更进一步的管道:
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score
rkf = RepeatedKFold(n_splits=2, n_repeats=3, random_state=1)
pipeline = Pipeline(steps=[('s',rfe),('m',DecisionTreeClassifier())])
precisions = cross_val_score(pipeline, X, y, scoring='precision', cv=rkf)
print('Average precision:', np.mean(precisions))
"""
Average precision: 0.93
"""
综上所述,当原始数据传递给Pipeline时,后者:
- 在训练和测试数据中拆分它;
- 对训练数据调用
RFE.fit_transform()
; - 对测试数据应用
RFE.transform()
,使其包含相同的特征; - 对训练数据调用
estimator.fit()
以拟合(即训练)模型; - 调用
estimator.predict()
测试数据进行预测。 - 将预测值与实际值进行比较,并在内部保存性能结果(您传递给
scoring
参数的结果)。 - 对交叉验证过程中的每个拆分重复步骤 1-6
在程序结束时,有人可以访问性能结果并在各个折叠中取平均值。