【问题标题】:How do I add external features to my pipeline?如何将外部功能添加到我的管道?
【发布时间】:2021-02-13 21:39:37
【问题描述】:

很多年前这里也有类似的问题,但没有答案。我也有同样的问题。我想在构建Pipeline 并执行GridSearch 之前将新的数据列(在我的情况下为虚拟变量的3 列)添加到稀疏矩阵(来自TfidfVectorizer)并执行GridSearch 以找到最好的超参数。

目前,我可以在没有GridSearchPipeline 的情况下使用下面的代码逐个模型进行此操作。

# this is an NLP project
X = df["text"] # column of text
y = df["target"] # continuous target variable
X_train, X_unseen, y_train, y_unseen = train_test_split(X, y, test_size=0.5, stratify=df_merged["platform"], random_state=42)

# vectorize
tvec = TfidfVectorizer(stop_words="english")
X_train_tvec = tvec.fit_transform(X_train)

# get dummies
dummies = pd.get_dummies(df["dummies"]).values
# add dummies to tvec sparse matrix
X_train_tvec_dumm = hstack([X_train_tvec, dummies]).toarray()

从这里,我可以将我的模型拟合到 X_train_tvec_dumm 训练数据上,其中包括来自 TfidfVectorizer 的词向量的稀疏矩阵(形状:n_rows,n_columns)和 3 个虚拟列。因此最终的形状是 (n_rows, n_columns + 3)。

我尝试如下构建Pipeline

# get dummies
dummies = pd.get_dummies(df["dummies"]).values

def add_dummies(matrix):
    return hstack([matrix, dummies]).toarray()


pipe = Pipeline([
    ("features", FeatureUnion([
        ("tvec", TfidfVectorizer(stop_words="english")),
        ("dummies", add_dummies(??))    <-- how do I add this step into the pipeline?
    ])),
    ("ridge", RidgeCV())
])

pipe_params = {
    'features__tvec__max_features': [200, 500],
    'features__tvec__ngram_range': [(1,1), (1,2)]
}

gs = GridSearchCV(pipe, param_grid=pipe_params, cv=4)
gs.fit(X_train, y_train)
print(gs.best_score_)

tutorial 描述了如何为Pipeline 构建自定义转换器,但其自定义函数添加了一个通过在 X_train 上进行转换而设计的新功能。不幸的是,我的虚拟变量在 X_train 集之外。

【问题讨论】:

    标签: python scikit-learn pipeline gridsearchcv feature-engineering


    【解决方案1】:

    使用来自sklearn.preprocessingOneHotEncoder 代替来自pandas 的get_dummies,以及来自sklearn.composeColumnTransformer。制作一个包含“text”和“category|dummies”列作为特征的DataFrame。

    OneHotEncoder 需要整数类型的功能。如果您的功能不是 int 类型,请先将它们编码|映射为 int,然后应用 OneHotEncoder

    # ...
    from sklearn.compose import ColumnTransformer
    from sklearn.pipeline import Pipeline
    from sklearn.impute import SimpleImputer
    from sklearn.preprocessing import OneHotEncoder
    
    
    text_features = ['text']
    text_transformer = Pipeline(steps=[
        ('vectorizer', TfidfVectorizer(stop_words="english"))])
    
    categorical_features = ['category']
    categorical_transformer = Pipeline(steps=[
        ('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
        ('onehot', OneHotEncoder(handle_unknown='ignore'))])
    
    preprocessor = ColumnTransformer(
        transformers=[
            ('text', text_transformer, text_features),
            ('cat', categorical_transformer, categorical_features)])
    
    
    pipe =  Pipeline(steps=[('preprocessor', preprocessor),
                       ("ridge", RidgeCV())
    ])
    
    # ...
    
    
    
    

    【讨论】:

    • 感谢您的解决方案!我不知道ColumnTransformer。我将补充一点,对于列中的文本进行矢量化,它应该是 text_features = "text" 没有方括号,否则你最终会得到一个 1x1 的稀疏矩阵。
    猜你喜欢
    • 2019-11-08
    • 2016-04-17
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    • 1970-01-01
    • 2011-07-31
    • 1970-01-01
    • 2021-03-26
    相关资源
    最近更新 更多