仅在 scikit-learn 中对特征子集使用 PCA 的管道

Dav*_*idS 3 python scikit-learn

我有一组要建模的特征,其中一个实际上是在 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)
Run Code Online (Sandbox Code Playgroud)

eic*_*erg 5

scikit learn中开箱即用是不可能的。为了能够利用的全部功能Pipeline,并GridSearchCV考虑创建一个对象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
Run Code Online (Sandbox Code Playgroud)

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

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])
Run Code Online (Sandbox Code Playgroud)

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