如何创建包含内置scikit-learn变换器、自定义变换器的预处理管道,其中一个变换器用于特征工程?

我正在使用的数据集:

https://www.kaggle.com/shahir/protein-data-set

总结

我正在努力创建一个预处理管道,包含内置变换器和自定义变换器,其中一个变换器将添加额外的属性到数据中,并进一步对添加的属性进行变换。

额外属性的例子:

  • 有一个phValue属性,其中有缺失数据。我希望尝试创建一个额外的属性,在phLabel列中将phValue标记为(酸性、中性、碱性)。
  • 还有每个序列特征的字符串长度。

这将需要对phValue的缺失值进行填补,然后创建额外属性,并进一步变换序列长度属性。

我的糟糕变换器

这是一个我如何创建自定义变换器的例子,我可以用它进行手动预处理,但这不是创建完整预处理管道的正确方法。

def data_to_frame(X):    if isinstance(X, pd.DataFrame):        return X    elif isinstance(X, sparse.csr_matrix):        return pd.DataFrame(X, indices, atributes)    elif isinstance(X, np.ndarray):        return pd.DataFrame(X, indices, atributes)    else:        raise Exception("Incorrect Data Structure Passed")class CombinedAttributesAdder(BaseEstimator, TransformerMixin):    def __init__(self, no_difference = True): # no *args or **kargs        self.no_difference = no_difference    def fit(self, X, y=None):        return self # nothing else to do    def transform(self, X):        atributes.extend(['sequence_length', 'difference', 'phLabel'])        sequence_length = X.sequence.str.len()        difference = X['residueCount'] - sequence_length        phLabel = X['phValue'].apply(ph_labels)        if self.no_difference:            atributes.append('no_difference')            no_difference = (difference == 0)            return np.c_[X, sequence_length, difference, phLabel, no_difference]        else:            return np.c_[X, sequence_length, difference, phLabel]

变换器中的Pandas操作

我想在变换器中执行的操作是特定于pandas的。我的解决方案是将输入的numpy数组转换为数据框,并在transform函数中将其作为numpy数组返回。我使用全局变量来存储属性和索引。我意识到这是一个缺乏深度的做法。我如何在自定义变换器中使用pandas操作?

我看到了这篇博客文章,但无法使用Column Transformer实现:https://zablo.net/blog/post/pandas-dataframe-in-scikit-learn-feature-union/

更新:

我的管道中的其他问题。当指定要变换的列时,后续的变换器如何工作?它是否将整个集合传递给每个变换器,操作指定的列,并将修改后的完整集合返回给其他变换器?此外,对于自定义变换器不指定列似乎会引发错误,尽管在我的情况下它们是非功能性的,因为我将参数传递给了构造函数。我应该如何修改我的代码?

如果我在fit_transform之后注释掉OrdinalEncoder和OneHotEncoder,ColumnTransformer输出一个形状为(rows, 72)的numpy数组。我的数据中有19个属性,我在FeatureSelector变换器中删除了2个属性。所以我期望在没有OHE的情况下收到一个形状为(rows, 17)的数组。

如果我保持原样,我会收到一个:ValueError: Input contains NaN.

attributes是我数据集中每一列的全局数组。我在FeatureSelector中删除了我丢弃的值。

# numeric_feat_eng + categ_feat_eng 包含我所有的属性prepoc_pipeline = make_column_transformer(                  (SimpleImputer(strategy='mean'), numeric_feat_eng),                  (SimpleImputer(strategy='most_frequent'), categ_feat_eng),                  (FixAtributeValues(), attributes),                  (CombinedAttributesAdder(), attributes),                  (FeatureSelector(attributes_to_drop), attributes_to_drop),                  (LogTransformation(atr_log_trans), atr_log_trans),                  (StandardScaler(), numeric_feat_eng),                  (OrdinalEncoder(), id_cols),                  (OneHotEncoder(handle_unknown='ignore'), categ_without_ids))
class FeatureSelector(BaseEstimator, TransformerMixin):    def __init__(self, attributes_drop = ['pdbxDetails', 'sequence']):        self.attributes_drop = attributes_drop    def fit(self, X, y=None):        return self # nothing else to do    def transform(self, X):        X = data_to_frame(X)        for x in self.attributes_drop:            attributes.remove(x)        X = X.drop(columns=self.attributes_drop)        return X

如果有人能指导我如何做这件事,我将非常感激!或者提供我可以学习如何创建管道的资源。


回答:

这应该按预期工作 – 最有可能的是你的实现有问题 – 可以尝试使用一个虚拟数据集。 TransformerMixin并不真正关心输入是 numpy 还是 pandas.DataFrame,它会按“预期”工作。

import pandas as pdimport numpy as npfrom sklearn.base import TransformerMixinfrom sklearn.preprocessing import StandardScalerfrom sklearn.preprocessing import FunctionTransformerfrom sklearn.pipeline import make_pipelineclass CustomTransformer(TransformerMixin):    def __init__(self, some_stuff=None, column_names= []):        self.some_stuff = some_stuff        self.column_names = column_names    def fit(self, X, y=None):        return self    def transform(self, X):        # 对X进行操作,并返回相同形状的数据框        # 如果前面的项目是numpy数组而不是数据框,这会变得很复杂        if isinstance(X, np.ndarray):            X = pd.DataFrame(X, columns=self.column_names)                X['str_len'] = X['my_str'].apply(lambda x: str(x)).str.len()        X['custom_func'] = X['val'].apply(lambda x: 1 if x > 0.5 else -1)        return Xdf = pd.DataFrame({    'my_str': [111, 2, 3333],    'val': [0, 1, 1]})# 混合使用这按预期工作my_pipeline = make_pipeline(StandardScaler(), CustomTransformer(column_names=["my_str", "val"]))my_pipeline.fit_transform(df)# 单独使用这也工作my_pipeline = make_pipeline(CustomTransformer(column_names=["my_str", "val"]))my_pipeline.fit_transform(df)

输出为:

In [  ]: my_pipeline = make_pipeline(StandardScaler(), CustomTransformer(column_names=["my_str", "val"]))     ...: my_pipeline.fit_transform(df)                                                                                                                                                                                                  Out[  ]:      my_str       val  str_len  custom_func0 -0.671543 -1.414214       19           -11 -0.742084  0.707107       18            12  1.413627  0.707107       17            1In [  ]: my_pipeline = make_pipeline(CustomTransformer(column_names=["my_str", "val"]))     ...: my_pipeline.fit_transform(df)                                                                                                                                                                                                  Out[  ]:    my_str  val  str_len  custom_func0     111    0        3           -11       2    1        1            12    3333    1        4            1

或者,如果你想直接将事物映射到数据框,你可以使用 sklearn-pandas

from sklearn_pandas import DataFrameMapper# 使用sklearn-pandasstr_transformer = FunctionTransformer(lambda x: x.apply(lambda y: y.str.len()))cust_transformer = FunctionTransformer(lambda x: (x > 0.5) *2 -1)mapper = DataFrameMapper([    (['my_str'], str_transformer),    (['val'], make_pipeline(StandardScaler(), cust_transformer))], input_df=True, df_out=True)mapper.fit_transform(df)

输出为:

In [  ]: mapper.fit_transform(df)                                                                                                                                                                                                       Out[47]:    my_str  val0       3   -11       2    12       1    1

使用sklearn pandas可以更具体地指定输入和输出为数据框,并允许你将每个列单独映射到每个感兴趣的管道,而不是将列名编码/硬编码为 TransformerMixin 对象的一部分。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注