Skip to content

Commit c1abc20

Browse files
committed
DOC add multioutput guide
1 parent 4504665 commit c1abc20

File tree

5 files changed

+123
-2
lines changed

5 files changed

+123
-2
lines changed

doc/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ API Reference
2323
Useful Links
2424
------------
2525
.. toctree::
26+
:maxdepth: 2
2627

2728
User Guild <user_guide>
2829
Examples <auto_examples/index>

doc/multioutput.rst

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,52 @@
66
Multioutput feature selection
77
==============================
88

9-
We can use :class:`FastCan` to handle multioutput feature selection.
9+
We can use :class:`FastCan` to handle multioutput feature selection, which means
10+
target ``y`` can be a matrix. For regression, :class:`FastCan` can be used for
11+
MIMO (Multi-Input Multi-Output) data. For classification, it can be used for
12+
multilabel data. Actually, for multiclass classification, which has one output with
13+
multiple categories, multioutput feature selection can also be useful. The multiclass
14+
classification can be converted to multilabel classification by one-hot encoding
15+
target ``y``. The cannonical correaltion coefficient between the features ``X`` and the
16+
one-hot encoded target ``y`` has equivalent relationship with Fisher's criterion in
17+
LDA (Linear Discriminant Analysis) [1]_. Applying :class:`FastCan` to the converted
18+
multioutput data may result in better accuracy in the following classification task
19+
than applying it directly to the original single-label data. See Figure 5 in [2]_.
20+
21+
Relationship on multiclass data
22+
-------------------------------
23+
Assume the feature matrix is :math:`X \in \mathbb{R}^{N\times n}`, the multiclass
24+
target vector is :math:`y \in \mathbb{R}^{N\times 1}`, and the one-hot encoded target
25+
matrix is :math:`Y \in \mathbb{R}^{N\times m}`. Then, the Fisher's criterion for
26+
:math:`X` and :math:`y` is denoted as :math:`J` and the canonical correaltion
27+
coefficient between :math:`X` and :math:`Y` is denoted as :math:`R`. The relationship
28+
between :math:`J` and :math:`R` is given by
29+
30+
.. math::
31+
J = \frac{R^2}{1-R^2}
32+
33+
or
34+
35+
.. math::
36+
R^2 = \frac{J}{1+J}
37+
38+
It should be noted that the number of the Fisher's criterion and the canonical
39+
correaltion coefficient is not only one. The number of the non-zero canonical
40+
correlation coefficients is no more than :math:`\min (n, m)`, and each canonical correlation
41+
coefficient is one-to-one correspondence to each Fisher's criterion.
42+
43+
.. rubric:: References
44+
45+
.. [1] `"Orthogonal least squares based fast feature selection for
46+
linear classification" <https://doi.org/10.1016/j.patcog.2021.108419>`_
47+
Zhang, S., & Lang, Z. Q. Pattern Recognition, 123, 108419 (2022).
48+
49+
.. [2] `"Canonical-correlation-based fast feature selection for structural
50+
health monitoring" <https://doi.org/10.1016/j.ymssp.2024.111895>`_
51+
Zhang, S., Wang, T., Worden, K., Sun L., & Cross, E. J.
52+
Mechanical Systems and Signal Processing, 223, 111895 (2025).
53+
54+
.. rubric:: Examples
55+
56+
* See :ref:`sphx_glr_auto_examples_plot_fisher.py` for an example of
57+
the equivalent relationship between CCA and LDA on multiclass data.

doc/redundancy.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ which gives large rounding-errors when linearly redundant features appears.
2727
* `"Canonical-correlation-based fast feature selection for structural
2828
health monitoring" <https://doi.org/10.1016/j.ymssp.2024.111895>`_
2929
Zhang, S., Wang, T., Worden, K., Sun L., & Cross, E. J.
30-
Mechanical Systems and Signal Processing, 223:111895 (2025).
30+
Mechanical Systems and Signal Processing, 223, 111895 (2025).
3131

3232
.. rubric:: Examples
3333

doc/user_guide.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ User Guide
66

77
.. toctree::
88
:numbered:
9+
:maxdepth: 1
910

1011
intuitive.rst
1112
unsupervised.rst

examples/plot_fisher.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
"""
2+
=========================
3+
Fisher's criterion in LDA
4+
=========================
5+
6+
.. currentmodule:: fastcan
7+
8+
In this examples, we will demonstrate the cannonical correaltion coefficient
9+
between the features ``X`` and the one-hot encoded target ``y`` has equivalent
10+
relationship with Fisher's criterion in LDA (Linear Discriminant Analysis).
11+
"""
12+
13+
# Authors: Sikai Zhang
14+
# SPDX-License-Identifier: MIT
15+
16+
# %%
17+
# Prepare data
18+
# ------------
19+
# We use ``iris`` dataset and transform this multiclass data to multilabel data by
20+
# one-hot encoding. Here, drop="first" is necessary, otherwise, the transformed target
21+
# is not full column rank.
22+
23+
from sklearn import datasets
24+
from sklearn.preprocessing import OneHotEncoder
25+
26+
27+
X, y = datasets.load_iris(return_X_y=True)
28+
# drop="first" is necessary, otherwise, the transformed target is not full column rank
29+
y_enc = OneHotEncoder(
30+
drop="first",
31+
sparse_output=False,
32+
).fit_transform(y.reshape(-1, 1))
33+
34+
# %%
35+
# Compute Fisher's criterion
36+
# --------------------------
37+
# The intermediate product of ``LinearDiscriminantAnalysis`` in ``sklearn`` is
38+
# Fisher's criterion, when ``solver="eigen"``. However, it does not provide an interface
39+
# to export it, so we reproduce it manually.
40+
41+
import numpy as np
42+
from scipy import linalg
43+
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
44+
from sklearn.covariance import empirical_covariance
45+
46+
clf = LinearDiscriminantAnalysis(solver="eigen").fit(X, y)
47+
Sw = clf.covariance_ # within scatter
48+
St = empirical_covariance(X) # total scatter
49+
Sb = St - Sw # between scatter
50+
fishers_criterion, _ = linalg.eigh(Sb, Sw)
51+
52+
fishers_criterion = np.sort(fishers_criterion)[::-1]
53+
n_nonzero = min(X.shape[1], clf.classes_.shape[0]-1)
54+
# remove the eigenvalues which are close to zero
55+
fishers_criterion = fishers_criterion[:n_nonzero]
56+
# get canonical correlation coefficients from convert Fisher's criteria
57+
r2 = fishers_criterion/(1+fishers_criterion)
58+
59+
# %%
60+
# Compute SSC
61+
# -----------
62+
# Compute the sum of squared canonical correlation coefficients (SSC). It can be found
63+
# that the result obtained by :class:`FastCan`/CCA (Canonical Correlation Analysis) is
64+
# the same as LDA.
65+
66+
from fastcan import FastCan
67+
68+
ssc = FastCan(4, verbose=0).fit(X, y_enc).scores_.sum()
69+
70+
print(f"SSC from LDA: {r2.sum():5f}")
71+
print(f"SSC from CCA: {ssc:5f}")

0 commit comments

Comments
 (0)