1111)
1212from sklearn .linear_model ._base import LinearClassifierMixin
1313
14- from sklearn .base import MultiOutputMixin
1514from sklearn .multioutput import MultiOutputClassifier
1615from sklearn .svm import LinearSVC
1716from sklearn .utils import check_array
@@ -36,8 +35,8 @@ class PCovC(LinearClassifierMixin, _BasePCov):
3635 (1 - \alpha) \mathbf{Z}\mathbf{Z}^T
3736
3837 where :math:`\alpha` is a mixing parameter, :math:`\mathbf{X}` is an input matrix of shape
39- :math:`(n_{samples}, n_{features})`, and :math:`\mathbf{Z}` is a matrix of class confidence scores
40- of shape :math:`(n_{samples}, n_{classes})`. For :math:`(n_{samples} < n_{features})`,
38+ :math:`(n_{samples}, n_{features})`, and :math:`\mathbf{Z}` is a tensor of class confidence scores
39+ of shape :math:`(n_{samples}, n_{classes}, n_{labels} )`. For :math:`(n_{samples} < n_{features})`,
4140 this can be more efficiently computed using the eigendecomposition of a modified covariance matrix
4241 :math:`\mathbf{\tilde{C}}`
4342
@@ -112,10 +111,10 @@ class PCovC(LinearClassifierMixin, _BasePCov):
112111 - ``sklearn.linear_model.LogisticRegressionCV()``
113112 - ``sklearn.svm.LinearSVC()``
114113 - ``sklearn.discriminant_analysis.LinearDiscriminantAnalysis()``
115- - ``sklearn.multioutput.MultiOutputClassifier ()``
114+ - ``sklearn.linear_model.Perceptron ()``
116115 - ``sklearn.linear_model.RidgeClassifier()``
117116 - ``sklearn.linear_model.RidgeClassifierCV()``
118- - ``sklearn.linear_model.Perceptron ()``
117+ - ``sklearn.multioutput.MultiOutputClassifier ()``
119118
120119 If a pre-fitted classifier
121120 is provided, it is used to compute :math:`{\mathbf{Z}}`.
@@ -175,11 +174,15 @@ class PCovC(LinearClassifierMixin, _BasePCov):
175174 the projector, or weights, from the input space :math:`\mathbf{X}`
176175 to the latent-space projection :math:`\mathbf{T}`
177176
178- pxz_ : ndarray of size :math:`({n_{features}, })`, :math:`({n_{features}, n_{classes}})`
177+ pxz_ : ndarray of size :math:`({n_{features}, {n_{classes}}})`, or list of
178+ ndarrays of size :math:`({n_{features}, {n_{classes_i}}})` for a dataset
179+ with :math: `i` labels.
179180 the projector, or weights, from the input space :math:`\mathbf{X}`
180181 to the class confidence scores :math:`\mathbf{Z}`.
181182
182- ptz_ : ndarray of size :math:`({n_{components}, })`, :math:`({n_{components}, n_{classes}})`
183+ ptz_ : ndarray of size :math:`({n_{components}, {n_{classes}}})`, or list of
184+ ndarrays of size :math:`({n_{components}, {n_{classes_i}}})` for a dataset
185+ with :math: `i` labels.
183186 the projector, or weights, from from the latent-space projection
184187 :math:`\mathbf{T}` to the class confidence scores :math:`\mathbf{Z}`.
185188
@@ -267,7 +270,7 @@ def fit(self, X, Y, W=None):
267270 Classification weights, optional when classifier is ``precomputed``. If
268271 not passed, it is assumed that the weights will be taken from a
269272 linear classifier fit between :math:`\mathbf{X}` and :math:`\mathbf{Y}`.
270- In the multioutput case,
273+ In the multioutput case, use
271274 `` W = np.hstack([est_.coef_.T for est_ in classifier.estimators_])``.
272275 """
273276 X , Y = validate_data (self , X , Y , multi_output = True , y_numeric = False )
@@ -329,15 +332,15 @@ def fit(self, X, Y, W=None):
329332 W = np .hstack ([_ .coef_ .T for _ in _ .estimators_ ])
330333 else :
331334 W = _ .coef_ .T
332- else :
335+ elif W is None :
333336 self .z_classifier_ = check_cl_fit (classifier , X , Y )
334337 if multioutput :
335338 W = np .hstack ([est_ .coef_ .T for est_ in self .z_classifier_ .estimators_ ])
336339 else :
337340 W = self .z_classifier_ .coef_ .T
338341
339342 Z = X @ W
340-
343+
341344 if self .space_ == "feature" :
342345 self ._fit_feature_space (X , Y , Z )
343346 else :
@@ -348,19 +351,12 @@ def fit(self, X, Y, W=None):
348351 self .classifier_ = clone (classifier ).fit (X @ self .pxt_ , Y )
349352
350353 if multioutput :
351- self .ptz_ = np .hstack (
352- [est_ .coef_ .T for est_ in self .classifier_ .estimators_ ]
353- )
354- # print(f"pxt {self.pxt_.shape}")
355- # print(f"ptz {self.ptz_.shape}")
356- self .pxz_ = self .pxt_ @ self .ptz_
357- # print(f"pxz {self.pxz_.shape}")
354+ self .ptz_ = [est_ .coef_ .T for est_ in self .classifier_ .estimators_ ]
355+ self .pxz_ = [self .pxt_ @ ptz for ptz in self .ptz_ ]
358356 else :
359357 self .ptz_ = self .classifier_ .coef_ .T
360- # print(self.ptz_.shape)
361358 self .pxz_ = self .pxt_ @ self .ptz_
362359
363- # print(self.ptz_.shape)
364360 if not multioutput and type_of_target (Y ) == "binary" :
365361 self .pxz_ = self .pxz_ .reshape (
366362 X .shape [1 ],
@@ -531,3 +527,4 @@ def score(self, X, y, sample_weight=None):
531527
532528 # Inherit the docstring from scikit-learn
533529 score .__doc__ = LinearClassifierMixin .score .__doc__
530+
0 commit comments