【问题标题】:pipeline with PCA on feature subset only in scikit-learn仅在 scikit-learn 中在特征子集上使用 PCA 的管道
【发布时间】:2014-07-30 05:59:40
【问题描述】:

我有一组要建模的特征,其中一个实际上是在 100 个不同点采样的直方图。因此,这个直方图特征实际上是 100 个不同的特征。我想通过对直方图特征执行 PCA 来减少建模问题的维度,但是我不想在 PCA 中包含其他特征以保持模型的可解释性。

理想情况下,我想与 PCA 形成一个管道来转换直方图特征和 SVC 来执行拟合,我会将其馈送到 GridSearchCV 以确定 SVC 超参数。在这个设置中是否有可能让 PCA 只转换我的特征的一个子集(直方图箱)?最简单的方法是编辑 PCA 对象以接受功能掩码,但我当然更喜欢使用现有功能。

编辑

在实现@eickenberg 的回答后,我意识到我还想要一个用于新 PCA 类的 inverse_transform 方法。此方法使用原始顺序的列重新创建初始特征集。以下为有兴趣的人提供:

def inverse_transform(self, X):
    if self.mask is not None:
        # Inverse transform appropriate data
        inv_mask = np.arange(len(X[0])) >= sum(~self.mask)
        inv_transformed = self.pca.inverse_transform(X[:, inv_mask])

        # Place inverse transformed columns back in their original order
        inv_transformed_reorder = np.zeros([len(X), len(self.mask)])
        inv_transformed_reorder[:, self.mask] = inv_transformed
        inv_transformed_reorder[:, ~self.mask] = X[:, ~inv_mask]
        return inv_transformed_reorder
    else:
        return self.pca.inverse_transform(X)

【问题讨论】:

    标签: python scikit-learn


    【解决方案1】:

    这对于 scikit learn 是不可能的开箱即用。为了能够利用PipelineGridSearchCV 的全部功能,请考虑创建一个对象MaskedPCA,从sklearn.base.BaseEstimator 继承并公开方法fittransform。在其中,您应该在您的蒙面特征上使用 PCA 对象。掩码应该传递给构造函数。

    from sklearn.base import BaseEstimator, TransformerMixin
    from sklearn.decomposition import PCA
    
    class MaskedPCA(BaseEstimator, TransformerMixin):
    
        def __init__(self, n_components=2, mask=None):  
            # mask should contain selected cols. Suppose it is boolean to avoid code overhead
            self.n_components = n_components
            self.mask = mask
    
        def fit(self, X):
            self.pca = PCA(n_components=self.n_components)
            mask = self.mask
            mask = self.mask if self.mask is not None else slice(None)
            self.pca.fit(X[:, mask])
            return self
    
        def transform(self, X):
            mask = self.mask if self.mask is not None else slice(None)
            pca_transformed = self.pca.transform(X[:, mask])
            if self.mask is not None:
                remaining_cols = X[:, ~mask]
                return np.hstack([remaining_cols, pca_transformed])
            else:
                return pca_transformed
    

    您可以在一些生成的数据上对其进行测试

    import numpy as np
    X = np.random.randn(100, 20)
    mask = np.arange(20) > 4
    
    mpca = MaskedPCA(n_components=2, mask=mask)
    
    transformed = mpca.fit(X).transform(X)
    
    # check whether first five columns are equal
    from numpy.testing import assert_array_equal
    assert_array_equal(X[:, :5], transformed[:, :5])
    

    观察transformed 现在有(~mask).sum + mpca.n_components == 7

    【讨论】:

    • 非常感谢您的帮助,完美运行。为了完整起见,我还创建了一个 inverse_transform 方法。
    • 好点 - 我忘了。你能把你的inverse_transform 编辑成这个答案吗?
    • 好的,添加进去了。
    • 使用带有此处代码的管道也是一种可能的解决方案:github.com/scikit-learn/scikit-learn/issues/3560
    • 您的意思是使用FunctionTransformer?为什么不呢!
    猜你喜欢
    • 2019-05-02
    • 2019-02-14
    • 2017-03-09
    • 2016-11-30
    • 2016-10-11
    • 2014-06-11
    • 2019-10-22
    • 2021-03-17
    • 1970-01-01
    相关资源
    最近更新 更多