在scikit-learn中,仅对特征子集进行PCA管道

3
我有一组特征需要建模,其中一个特征是在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)
2个回答

5

使用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列。

1
非常感谢帮助,运行得非常完美。我还专门为了完整性创建了一个inverse_transform方法。 - DavidS
好的观点 - 我忘记了。你能否将你的“inverse_transform”编辑到这个答案中? - eickenberg
1
好的,已经添加进去了。 - DavidS
1
使用此处代码的管道也是一种可能的解决方案:https://github.com/scikit-learn/scikit-learn/issues/3560 - Andreas Mueller
你的意思是使用 FunctionTransformer 吗?为什么不呢! - eickenberg

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接