如何在 SelectKBest 之后仅将必要的功能传递给管道

How to pass only necessary features to pipeline after SelectKBest

提问人:Nikitosiwe 提问时间:8/19/2023 最后编辑:desertnautNikitosiwe 更新时间:8/21/2023 访问量:89

问:

我有一个常规的表格数据集,从数据库中添加了 100 个要素

我想把它推送到一个常规的sklearn.pipeline中,其中将有预处理、编码、一些自定义转换器等。

倒数第二个估计器是 SelectKBest(k=10)

实际上,对于模型,只需要 10 个特征,而管道将需要所有 100 个特征

我想在生产模型中只使用“必要”功能。我想避免额外的功能以减少计算时间。

当然,我可以重建管道,但整个 sklearn 就是不这样做。我不知道这在多大程度上是一种“标准”做法

我理解为什么它根本不起作用,因为 150 个功能实际上可以转到 SelectKBest 输入。在这种情况下,如何确定这些“必要”特征并不明显。

也许还有其他一些开箱即用的工具?

基本示例:

from sklearn.datasets import load_diabetes
from sklearn.preprocessing import StandardScaler
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline

data = load_diabetes(as_frame=True)
X, y = data.data, data.target

X = X.iloc[:, :10]

pipeline = Pipeline([
    ('scaler', StandardScaler()), 
    ('feature_selection', SelectKBest(score_func=f_regression, k=4)),
    ('model', LinearRegression())
])

pipeline.fit(X, y)

selected_features = pipeline.named_steps['feature_selection'].get_support()
selected_features = X.columns[selected_features]
print(f"Selected features: {selected_features}")
# Selected features: Index(['bmi', 'bp', 's4', 's5'], dtype='object')

prod_data = X[selected_features]

pred = pipeline.predict(prod_data)

# Here will be an Exception
# ValueError: The feature names should match those that were passed during fit.
# Feature names seen at fit time, yet now missing:
# - age
# - s1
# - s2
# - s3
# - s6
# - ...
scikit-learn 科学 特征 MLOps 数据工程

评论

0赞 some3128 8/19/2023
我的理解是,您有 100 个特征来自数据库,并且您正在使用一个管道,将 100 个特征处理为 10 个特征。然后,将这 10 个特征赋予模型。和最终模型是管道的一部分,还是与管道分开?听起来你需要管道将 100 个功能减少到 10 个 - 为什么你不能保留这个管道?SelectKBest
0赞 Community 8/19/2023
请提供足够的代码,以便其他人可以更好地理解或重现问题。
0赞 Nikitosiwe 8/20/2023
@some3128 例如,我添加了一些代码。
0赞 Nikitosiwe 8/20/2023
当然,我可以仅为特征选择设置初始管道(无需任何模型)。随后,我可以设计第二个管道,它本质上相似,但与模型集成,我将仅使用所选特征对其进行训练。但是,我不确定这是否是理想的方法。@some3128
0赞 some3128 8/20/2023
感谢您的澄清。请查看我发布的答案,并让我知道您的想法。

答:

1赞 some3128 8/20/2023 #1

在您的管道中,该步骤将负责保留 4 个功能,并删除其他功能。此步骤之后的模型将仅看到这 4 个功能。这是因为在内部,管道将在拟合数据后用于转换数据,因此该步骤仅传递 4 个选定的特征。SelectKBestSelectKBest

要使用所选要素获取预测,请运行 。这将在它们进入最终模型之前自动删除不必要的功能。我修改了你的代码:pipeline.fit(X, y).predict(X)

from sklearn.datasets import load_diabetes
from sklearn.preprocessing import StandardScaler
from sklearn.feature_selection import SelectKBest, f_regression
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline

data = load_diabetes(as_frame=True)
X, y = data.data, data.target

X = X.iloc[:, :10]

#Define the pipeline
pipeline = Pipeline([
    ('scaler', StandardScaler()), 
    ('feature_selection', SelectKBest(score_func=f_regression, k=4)),
    ('model', LinearRegression())
])

#Fit and predict. Final model only uses the k best features.
pred_using_selected_features = pipeline.fit(X, y).predict(X)

#Print results
selected_features = pipeline.named_steps['feature_selection'].get_support()
print(f"Selected features: {X.columns[selected_features].to_list()}")

print(f'Model saw {pipeline.named_steps["model"].n_features_in_} features')

enter image description here

在流水线的过程中,选择了 4 个特征,而模型只看到了这 4 个特征。

评论

0赞 Nikitosiwe 8/20/2023
当然,它有效。但是你传入了 predict 函数完整的 X 数据集(有 10 列)。我的问题是,如何减少这个列的数量,因为实际上模型只需要 4 个特征
0赞 some3128 8/20/2023
我完整地传递了,因为管道会自动过滤掉模型的 4 个特征。但是您希望从一开始就只传递 4 个功能?在这种情况下,我不确定是否有单管道解决方案。如果管道最初是在 10 个特征上训练的,那么它总是会在输入时要求 10 个特征,如果你提供的特征比训练时少,我认为它会出错。X
1赞 Nikitosiwe 8/20/2023 #2

我同意@some3128的观点,看起来没有单一的管道解决方案。

据我了解,像 SelectKBest 这样的估算器正在用于减少由 PolynomialFeatures、PCA 等其他估算器在 Pipeline 内部生成的特征。

当然,也许有一种方法可以确定最佳生成的特征,并防止在预测时生成无用的特征。但它更像是“低级”优化。

在流水线之前减少特征 - 这是关于特征工程过程,这是一个单独的问题。

2赞 Ben Reiniger 8/21/2023 #3

我通常建议您尝试避免的解决方案:重新构建管道,而不执行选择步骤,并且不使用训练集中删除的列。

可以识别和更改每个流水线步骤的拟合属性(从缩放器中删除条目等,减少和特征名称等),并且可以自动执行。但是弄乱内部结构有点风险:删除错误的东西不会产生错误,但每列执行错误的缩放。mean_scale_n_features_in_

另一个低技术含量的解决方案:您不在乎预测行中已删除列的值是多少,因此只需编造它们即可。sklearn 管道仍将处理假值,但无需在生产环境中收集这些字段。