在 Scikit-Learn 中连接多维降维算法
Posted
技术标签:
【中文标题】在 Scikit-Learn 中连接多维降维算法【英文标题】:Concatenating multiple dimensionality reduction algorithms in Scikit-Learn 【发布时间】:2018-05-26 07:37:13 【问题描述】:数据集由两个二维矩阵X
和Y
组成,n
行(测量次数)和m
columns 描述了每个测量的相应特征。从第一个矩阵中,我想获得内核 PCA 组件。此外,使用cross-decomposition 我想使用PLS and CCA 获得两个矩阵之间的线性关系。
目标是使用 Pipeline 为第一个矩阵的每一行 n
创建一个特征向量,该向量由其内核 PCA 分量以及其在 PLS 和 CCA 发现的潜在空间上的投影组成。对于矩阵X
的每一行,其特征向量应由支持向量机在二进制分类任务中进行分类,标签为train_labels
和test_labels
。因此,Y
矩阵仅用于计算投影X
的联合潜在空间。
考虑到 Kernel PCA 仅适用于 X_train 数据(第一个矩阵),而 PLS 和 CCA 同时适用于 X_train 和 Y_train(两个矩阵),实现这一目标的最佳方法是什么?
我的代码到现在为止(不工作):
n_comp = 3
plsca = PLSCanonical(n_components=n_comp)
cca = CCA(n_components=n_comp)
kpca = KernelPCA(kernel="rbf", fit_inverse_transform=False, gamma=10, n_components=n_comp)
x_tranf_kpca = kpca.fit_transform(X_train)
svm = SVC(probability=True, class_weight='balanced', tol=0.0001)
comb_feat_bna_sg = FeatureUnion([('pls_canonical', plsca), ('cca', cca)])
x_feats_bna_sg = comb_feat_bna_sg.fit(X_train, Y_train).transform(X_train)
pipe_bna = Pipeline([('kpca', kpca)])
pipe_bna_sg = Pipeline([("x_feats_bna_sg", comb_feat_bna_sg)])
combined_features = FeatureUnion([('bna', pipe_bna), ('bna_sg', pipe_bna_sg)])
pipe = Pipeline([("features", combined_features), ('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True)), ("svm", svm)])
# Parameters of pipelines can be set using ‘__’ separated parameter names:
param_pipe = dict(features__bna_sg__x_feats_bna_sg__pls_canonical__n_components=[1, 2],
features__bna_sg__x_feats_bna_sg__cca__n_components=[1, 2],
features__bna__kpca__n_components=[1, 2],
svm__kernel=["rbf"],
svm__C=[10],
svm__gamma=[1e-2]
)
clf = dcv.GridSearchCV(pipe, param_pipe, cv=10)
clf.fit(X_train, train_labels)
y_predict = clf.predict(X_test)
编辑 1
我认为该错误与here 所描述的错误密切相关,其中答案指出
关于在管道中使用 PLSSVD 的问题的答案 cross_val_score,否,它不会开箱即用,因为 管道对象调用 fit 和 transform 使用变量 X 和 Y 如果可能的话,作为参数,正如你在我写的代码中看到的那样, 返回一个包含投影 X 和 Y 值的元组。下一步 在管道中将无法处理这个,因为它会 认为这个元组是新的 X。
我的异常堆栈跟踪:
Traceback (most recent call last):
File "D:/Network/SK_classifier_orders_Pipeline.py", line 236, in <module>
train_svm_classifier()
File "D:/Network/SK_classifier_orders_Pipeline.py", line 127, in train_svm_classifier
clf.fit(X_train, train_labels)
File "C:\ProgramData\Anaconda3\lib\site-packages\dask_searchcv-0+unknown-py3.6.egg\dask_searchcv\model_selection.py", line 867, in fit
File "C:\ProgramData\Anaconda3\lib\site-packages\dask\threaded.py", line 75, in get
pack_exception=pack_exception, **kwargs)
File "C:\ProgramData\Anaconda3\lib\site-packages\dask\local.py", line 521, in get_async
raise_exception(exc, tb)
File "C:\ProgramData\Anaconda3\lib\site-packages\dask\compatibility.py", line 60, in reraise
raise exc
File "C:\ProgramData\Anaconda3\lib\site-packages\dask\local.py", line 290, in execute_task
result = _execute_task(task, data)
File "C:\ProgramData\Anaconda3\lib\site-packages\dask\local.py", line 271, in _execute_task
return func(*args2)
File "C:\ProgramData\Anaconda3\lib\site-packages\dask_searchcv-0+unknown-py3.6.egg\dask_searchcv\methods.py", line 187, in feature_union_concat
File "C:\ProgramData\Anaconda3\lib\site-packages\numpy\core\shape_base.py", line 288, in hstack
arrs = [atleast_1d(_m) for _m in tup]
File "C:\ProgramData\Anaconda3\lib\site-packages\numpy\core\shape_base.py", line 288, in <listcomp>
arrs = [atleast_1d(_m) for _m in tup]
File "C:\ProgramData\Anaconda3\lib\site-packages\numpy\core\shape_base.py", line 52, in atleast_1d
ary = asanyarray(ary)
File "C:\ProgramData\Anaconda3\lib\site-packages\numpy\core\numeric.py", line 583, in asanyarray
return array(a, dtype, copy=False, order=order, subok=True)
ValueError: could not broadcast input array from shape (5307,1) into shape (5307)
编辑 2
在为第一个矩阵 (X) 生成特征向量后,在流水线的最后一步中,应使用 SVM 将它们分为两类。训练数据的标签以二进制向量train_labels
的形式提供。
【问题讨论】:
那么问题出在哪里?什么不工作?你有什么错误吗?请发布完整的堆栈跟踪。此外,通过将单个转换器包装到 featureUnion 和管道中,您会不必要地使事情复杂化。保持简单。 我编辑了问题以包含堆栈跟踪和更多信息。如果您知道如何通过更简单的解决方案实现我的目标,请将其作为答案提供。 FeatureUnion 尝试合并来自plsca
和cca
的输出时出现此错误。由于这两个输出都包含一个形式为 (X_array, y_array) 的元组,其中 X_array 的形状为 [n_samples, n_comps],而 y_array 的形状为 [n_samples, n_targets]。所以请告诉我你想如何组合这些数组。您只想合并来自plsca
和cca
的X_arrays 还是想先将X_array 和y_array 连接成一个数组,然后再连接来自plsca
和cca
的单个数组?
我只对 X_arrays 的组合感兴趣(来自原始 X 矩阵的数据在 CCA 和 PLSCA 的联合潜在空间上的投影),然后它们与 kernelPCA 投影的组合X_矩阵。我不需要关节空间上的 Y 投影。
【参考方案1】:
根据 cmets 中的讨论,由于您只想组合每个输出的 X 部分,因此可以使用自定义转换器来完成,该转换器返回 PLSConical 或 CCA 返回的元组的第一个元素。
class CustomXySeparator(BaseEstimator, TransformerMixin):
def fit(self, X, y=None):
return self
def transform(self, X, y=None):
if y is None:
return X
return X[0]
def fit_transform(self, X, y=None):
return self.fit(X,y).transform(X,y)
n_comp = 3
plsca = PLSCanonical(n_components=n_comp)
x_plsca = plsca.fit_transform(X_train, Y_train)
cca = CCA(n_components=n_comp)
x_cca = cca.fit_transform(X_train, Y_train)
kpca = KernelPCA(kernel="rbf", fit_inverse_transform=False, gamma=10, n_components=n_comp)
comb_feat_bna_sg = FeatureUnion([('pls_onlyX', Pipeline([("pls", plsca), ('getX', CustomXySeparator())])),
('cca_onlyX', Pipeline([("cca", cca), ('getX', CustomXySeparator())]))])
x_feats_bna_sg = comb_feat_bna_sg.fit_transform(X_train, Y_train)
combined_features = FeatureUnion([('kpca', kpca),
("x_feats_bna_sg", comb_feat_bna_sg)])
svm = SVC(probability=True, class_weight='balanced', tol=0.0001)
pipe = Pipeline([("features", combined_features),
('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True)),
("svm", svm)])
# Parameters of pipelines can be set using ‘__’ separated parameter names:
param_pipe = dict(features__x_feats_bna_sg__pls_onlyX__pls__n_components=[1, 2],
features__x_feats_bna_sg__cca_onlyX__cca__n_components=[1, 2],
features__kpca__n_components=[1, 2],
svm__kernel=["rbf"],
svm__C=[10],
svm__gamma=[1e-2]
)
clf = GridSearchCV(pipe, param_pipe, cv=10)
clf.fit(X_train, Y_train)
y_predict = clf.predict(X_test)
请注意,我已经删除了像pipe_bna = Pipeline([('kpca', kpca)])
这样的单个转换器上不必要的管道包装,并相应地更改了参数名称。请通过它一次。有什么不懂就问。
【讨论】:
谢谢!我不完全理解的是:在我上面的代码中,我有clf.fit(X_train, train_labels)
。 SVM 应该使用来自 CCA、PLSCA 和 KPCA 的 X 特征向量,并使用train_labels
执行(二进制)分类。在新代码中,我再也看不到 train_labels
的任何用法了?
@AlexGuevara train_labels 到底是什么?您是如何在代码中创建 X_train 和 Y_train 的?
@AlexGuevara 啊,是的,他们会的。在这种情况下,您需要将 svm 从管道的其余部分中分离出来。但这将限制 GridSearchCV 的使用。我猜您可能需要另一个自定义转换器,它将同时考虑 Y_train 和 train_labels 并将它们传递给适当的东西。
@AlexGuevara 为什么不将 Y_train 和 train_labels 合并到单个数组中,然后使用自定义转换器决定将什么发送到 svc 以及将什么发送到其他管道。这样,当 GridSearchCV 使用交叉验证并将数据拆分为 train 和 test 时,Y_train 和 train_label 被拆分在一起。
是的。由于两者的行相同,我们可以轻松地将它们连接起来。可能在 Y_train 的最后一个附加 train_labels 并根据需要分开。你说什么?如果您同意,我们可以对此进行自定义包装。以上是关于在 Scikit-Learn 中连接多维降维算法的主要内容,如果未能解决你的问题,请参考以下文章
主成分分析法(PCA)(含SVD奇异值分解)等降维(dimensionality reduction)算法-sklearn