管道中的 Scikit-Learn FunctionTransformer 没有其他功能 - 不返回原始数据?

Posted

技术标签:

【中文标题】管道中的 Scikit-Learn FunctionTransformer 没有其他功能 - 不返回原始数据?【英文标题】:Scikit-Learn FunctionTransformer in pipeline with no other functionality - not returning original data? 【发布时间】:2016-09-11 18:31:21 【问题描述】:

我正在尝试在 Python 2.7 的 Scikit-Learn 管道中运行自定义转换器 FunctionTransformer()。我使用了文档here 中的示例。此示例执行 PCA,然后仅选择第二个转换的组件。即转换一个 NumPy 数组 X 并提取转换后的 NumPy 数组的第二列。

我对官方文档中的代码所做的更改如下:

    从管道中删除 PCA() 添加 2 个打印语句以查看管道之前的 X 和管道之后的 X 删除了训练测试拆分 - 这样我使用 X 进行训练,然后转换 X 注释掉所有绘图代码

这是完整的工作代码:

import matplotlib.pyplot as plt
import numpy as np
from sklearn.cross_validation import train_test_split
from sklearn.decomposition import PCA
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import FunctionTransformer

def _generate_vector(shift=0.5, noise=15):
    return np.arange(1000) + (np.random.rand(1000) - shift) * noise

def generate_dataset():
    """
    This dataset is two lines with a slope ~ 1, where one has
    a y offset of ~100
    """
    return np.vstack((
        np.vstack((
            _generate_vector(),
            _generate_vector() + 100,
        )).T,
        np.vstack((
            _generate_vector(),
            _generate_vector(),
        )).T,
    )), np.hstack((np.zeros(1000), np.ones(1000)))
  
def all_but_first_column(X):
    return X[:, 1:]

def drop_first_component(X, y):
    """
    Create a pipeline with PCA and the column selector and use it to
    transform the dataset.
    """
    pipeline = make_pipeline(
        FunctionTransformer(all_but_first_column),
    )
    pipeline.fit(X,y)
    return pipeline.transform(X), y

if __name__ == '__main__':
    X, y = generate_dataset()
    print X[:20,:]
    X_transformed, y_transformed = drop_first_component(*generate_dataset())
    print X_transformed[:20,:]

当我运行这段代码时,我得到以下输出:

流水线前:

[[ -9.54109780e-01   1.00849257e+02]
 [ -6.44868525e+00   9.89713451e+01]
 [  6.00611903e+00   9.86368545e+01]
 [ -1.02307489e-01   9.91617270e+01]
 [  1.12423836e+01   1.04240711e+02]
 [  6.94957296e+00   1.09557543e+02]
 [  5.41042855e+00   1.09859950e+02]
 [  9.54984210e-01   1.03636786e+02]
 [  1.11194327e+01   1.06942524e+02]
 [  1.32146748e+01   1.16489221e+02]
 [  1.72316993e+01   1.16995924e+02]
 [  1.22797187e+01   1.08568249e+02]
 [  1.14360695e+01   1.06799741e+02]
 [  1.75291161e+01   1.13610682e+02]
 [  1.38768685e+01   1.07815267e+02]
 [  1.29773817e+01   1.12404830e+02]
 [  1.54218007e+01   1.11786074e+02]
 [  1.73923980e+01   1.19284226e+02]
 [  1.97373775e+01   1.16807048e+02]
 [  1.26896716e+01   1.26467393e+02]]

流水线后:

[[  94.35392453]
 [ 107.08036958]
 [  96.42404642]
 [  96.07304368]
 [ 109.33207232]
 [ 102.67435761]
 [ 106.34131846]
 [ 108.45857447]
 [ 105.33376831]
 [ 107.79576699]
 [ 110.71367112]
 [ 116.73589447]
 [ 117.74629814]
 [ 112.48947773]
 [ 109.7573836 ]
 [ 121.95472733]
 [ 119.62476775]
 [ 120.0264124 ]
 [ 115.00315794]
 [ 120.60368954]]

来自这个 Github post,它提到FunctionTransformer() 可以用来做一些简单的事情。我希望只在管道中放置一列。

流水线前后的 X 不同。如果我只想让管道删除 X 的最后一列,那么该管道是否应该在管道之前和之后返回相同的 X?

其他信息(如有必要):

在我的最终应用程序中,我需要使用转换器作为管道的第一步,然后在第二站使用PCA()。因此,我首先在这篇文章中测试管道,仅第一步 - FunctionTransformer()

【问题讨论】:

【参考方案1】:

您对generate_dataset() 进行了两次调用,因此您的drop_first_component 函数正在处理的矩阵不是Xy,而是一些新生成的数据。

将相同的(X, y) 直接传递给generate_dataset 可以解决问题:

if __name__ == '__main__':
  X, y = generate_dataset()
  print X[:20, :]
  X_transformed, y_transformed = drop_first_component(X, y)
  print X_transformed[:20, :]

也就是说,我认为在这里使用管道阶段完全是矫枉过正。您正在导入一些额外的库,包括几个额外的配置和逻辑行,这些行分布在三个函数中——所有这些都是为了一个除了简单的列 select X[:, 1:] 之外什么都不做的计算。

【讨论】:

非常感谢。这对我解释了很多!对于管道部分,正如我在 OP 的附加信息中提到的那样,接下来我将在流程中添加一个 PCA 步骤,以便管道在那里会有所帮助。就目前而言,你是对的,我不需要它。再次感谢。

以上是关于管道中的 Scikit-Learn FunctionTransformer 没有其他功能 - 不返回原始数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 scikit-learn 管道中的 CountVectorizer 之前包含 SimpleImputer?

管道中的 Scikit-Learn FunctionTransformer 没有其他功能 - 不返回原始数据?

使用 GridSearchCV scikit-learn 在管道中的 KMeans

如何在 scikit-learn 中使用管道调整自定义内核函数的参数

特征不匹配:通过 scikit-learn 管道进行预测

从磁盘加载包含预训练 Keras 模型的 scikit-learn 管道