如何仅在某些值上在管道内使用 StandardScaler?

Posted

技术标签:

【中文标题】如何仅在某些值上在管道内使用 StandardScaler?【英文标题】:How to use StandardScaler inside a pipeline only on certain values? 【发布时间】:2022-01-20 23:16:45 【问题描述】:

我有问题。我想使用StandardScaler(),但我的数据集包含某些OneHotEncoding 值和其他应该缩放的值。但是如果我运行StandardScaler(),所有的值都会被缩放。那么是否可以选择仅对管道内的某些值运行此方法?

我发现了这个问题:One-Hot-Encode categorical variables and scale continuous ones simultaneouely 使用以下代码

columns = ['rank']
columns_to_scale  = ['gre', 'gpa']

scaler = StandardScaler()
ohe    = OneHotEncoder(sparse=False)

# Concatenate (Column-Bind) Processed Columns Back Together
processed_data = np.concatenate([scaled_columns, encoded_columns], axis=1)

那么有没有一个选项只在 pipeline 内运行 StandardScaler() 在某些值上,而其他值应该合并到缩放值? 所以管道应该只对值'xy', 'xyz'使用StandardScaler。

标准缩放器类

from sklearn.base import BaseEstimator, TransformerMixin
class StandardScaler_with_certain_features(BaseEstimator, TransformerMixin):
    def __init__(self, columns_to_scale):
        scaler = StandardScaler()
        

    def fit(self, X, y = None):
        scaler.fit(X_train) # only std.fit on train set
        X_train_nor = scaler.transform(X_train.values)

    def transform(self, X, y = None):
        return X

管道

columns_to_scale  = ['xy', 'xyz']
    
steps = [('standard_scaler', StandardScaler_with_certain_features(columns_to_scale)),
         ('feature_selection', SelectFromModel(estimator=LogisticRegression(max_iter=100))),
         ('lasso', Lasso(alpha=0.03))]

pipeline = Pipeline(steps) 

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=30)

parameteres =  

grid = GridSearchCV(pipeline, param_grid=parameteres, cv=5)                
grid.fit(X_train, y_train)
                    
print("score = %3.2f" %(grid.score(X_test,y_test)))
print('Training set score: ' + str(grid.score(X_train,y_train)))
print('Test set score: ' + str(grid.score(X_test,y_test)))

# Prediction
y_pred = grid.predict(X_test)
print("RMSE Val:", metrics.mean_squared_error(y_test, y_pred, squared=False))

【问题讨论】:

不确定我是否明白你的意思,因为你提到的帖子似乎已经指定了实现你想要的常用技术,但也许我误解了这个问题...... 我看到的另一个选项(除了答案给出的那个)可能是创建一个类,而不是像你正在做的那样应用缩放,以某种方式选择你想要应用缩放的列;那么您可以在首先选择列然后应用缩放的管道中调用其构造函数。 【参考方案1】:

您可以在Pipeline 中包含ColumnTransformer,以便将StandardScaler 仅应用于某些列。您需要设置remainder='passthrough 以确保未缩放的列与已缩放的列连接。

import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.linear_model import Lasso

df = pd.DataFrame(
    'y': np.random.normal(0, 1, 100),
    'x': np.random.normal(0, 1, 100),
    'z': np.random.normal(0, 1, 100),
    'xy': np.random.normal(2, 3, 100),
    'xyz': np.random.normal(4, 5, 100),
)

X = df.drop(labels=['y'], axis=1)
y = df['y']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=30)

preprocessor = ColumnTransformer(
    transformers=[('scaler', StandardScaler(), ['xy', 'xyz'])],
    remainder='passthrough'
)

pipeline = Pipeline([
    ('preprocessor', preprocessor),
    ('lasso', Lasso(alpha=0.03))
])

pipeline.fit(X_train, y_train)
pipeline.score(X_test, y_test)

【讨论】:

非常感谢。但是如果我运行你的代码,我会得到ValueError: A given column is not a column of the dataframe KeyError: 'xy' 这意味着在具有特征值的数据框中没有名称为'xy' 的列。您需要仔细检查 X_trainX_test 的列名,并确保将需要缩放的列的正确名称传递给列转换器。 感谢您的快速回答。对此,我真的非常感激。是否可以选择使用 X_train 和 X_test 获得相同的结果? 我的意思是,当我使用X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=30) 运行您的代码时,我遇到了上述错误。那么是否可以选择将您的代码与测试/训练拆分一起使用? 我更新了答案中的代码,但是当您定义列转换器时,您需要确保将 ['xy', 'xyz'] 替换为包含需要缩放的列的实际名称的列表。

以上是关于如何仅在某些值上在管道内使用 StandardScaler?的主要内容,如果未能解决你的问题,请参考以下文章

amCharts 4:仅在截断的(带省略号)值上显示图例工具提示

为啥 LWJGL 仅在 Windows 上在以前和当前的游戏状态之间闪烁?

如何聚焦光线或如何仅在 pygame 中绘制窗口的某些圆形部分?

OpenCV 错误断言在某些像素值上失败

为啥 mkfifo'ed 管道仅在 ~25 秒后更新?

如何让 Gitlab CI 管道始终运行一些作业,而其他作业仅在合并请求上运行?