Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add class-distinctiveness function and its example code #215

Merged
merged 12 commits into from Dec 13, 2022

Conversation

msyamamoto
Copy link
Contributor

Hello everyone!

I am Maria Sayu Yamamoto.
I created a new function called class_distinctiveness that evaluates the degree of class separation between two classes of SPD matrices on the manifold.

This metric quantifies the class separability of the dataset based on the inter-class distance and the intra-class variance on the manifold, and it is originally proposed in the following reference:
Lotte, F., & Jeunet, C. (2018). Defining and quantifying users’ mental imagery-based BCI skills: a first step. Journal of neural engineering, 15(4), 046030.
https://iopscience.iop.org/article/10.1088/1741-2552/aac577/meta?casa_token=bZ_Sz-fcfXIAAAAA:_lr-H99Z4_Y-GrbxMgL6ELEOvx03b8I4Xa7gedXTciHcUdvz5TzQhGCZ1WGcKqNOOpWWRmbVKXx5

This can be used to select the optimal frequency band or time window on a manifold for enhancing the oscillatory activity classification performance, as it has been done in the following reference:
Yamamoto, M. S., Lotte, F., Yger, F., & Chevallier, S. (2022, July). Class-distinctiveness-based frequency band selection on the Riemannian manifold for oscillatory activity-based BCIs: preliminary results. In EMBC 2022-44th Annual International Conference of the IEEE Engineering in Medicine & Biology Society.
https://hal.archives-ouvertes.fr/hal-03641137/

I also made an example code to show how this metric works by generating toy datasets with different class separability levels.
This metric can extend to more than two classes as well.

I would appreciate your feedback and suggestions:-)

Sincerely,
Maria

pyriemann/featureselection.py Outdated Show resolved Hide resolved
pyriemann/featureselection.py Outdated Show resolved Hide resolved
pyriemann/featureselection.py Outdated Show resolved Hide resolved
pyriemann/featureselection.py Outdated Show resolved Hide resolved
pyriemann/featureselection.py Outdated Show resolved Hide resolved
…n scripts, move the function to preprocessing.py and delete featureselection.py
Copy link
Member

@qbarthelemy qbarthelemy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx Maria for this nice contribution!
Do not forget to add tests for your new function, for two and three classes.

pyriemann/preprocessing.py Outdated Show resolved Hide resolved
pyriemann/preprocessing.py Outdated Show resolved Hide resolved
pyriemann/preprocessing.py Outdated Show resolved Hide resolved
examples/simulated/plot_class_distinctiveness.py Outdated Show resolved Hide resolved
examples/simulated/plot_class_distinctiveness.py Outdated Show resolved Hide resolved
pyriemann/preprocessing.py Outdated Show resolved Hide resolved

def class_distinctiveness(X, y, nume_denomi=False):
"""Measure class separability between classes on a manifold.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write the formula for class distinctiveness value for k classes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I’m not super comfortable with the current formula of class distinctiveness.
Because Fisher criterion is defined as the ratio of the variance between the classes to the variance within the classes.
IMO, I think all distances in code should be at a power of 2.

We can solve this difference, adding a parameter p being the exponent of power:
p=2 will measure class dispersions with respect means, ie Frechet variances minimized during means estimation;
p=1 will measure class dispersions with respect medians, ie standard deviations.

Copy link
Contributor Author

@msyamamoto msyamamoto Dec 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a quick update, but when I was writing the formula for the documentation, I realized that my implementation of the second commit did not correctly reflect the equation of multi-class distinctiveness (Equation 7 in the original paper). I am sorry for that. I will modify it in the third commit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I am not sure if I fully understood your suggestion of using parameter p. That would be a different equation than the original paper's one, wouldn't it?
https://iopscience.iop.org/article/10.1088/1741-2552/aac577/meta?casa_token=bZ_Sz-fcfXIAAAAA:_lr-H99Z4_Y-GrbxMgL6ELEOvx03b8I4Xa7gedXTciHcUdvz5TzQhGCZ1WGcKqNOOpWWRmbVKXx5

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the article, a power of 2 was lost bewteen Eq(4) and Eq(5), giving a mean absolute deviation instead of a variance.

I suggest to add an argument $p$:
$$\mathrm{classDis}(A, B, p) = \frac{d \left(\bar{X}^{A}, \bar{X}^{B}\right)^p} {\frac{1}{2} \left( \sigma_{X^{A}}^p + \sigma_{X^{B}}^p \right)}$$
where
$$\sigma_{X^{K}}^p = \frac{1}{m} \sum_{i=1}^m d \left(X_i, \bar{X}^{K}\right)^p$$
When $p=1$, it gives equation from article.
When $p=2$, it really generalizes Fisher criterion, defined as the ratio of the variance between the classes to the variance within the classes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for the clear explanation! I got it!
Indeed, it is good for the user that they can choose from the two ways of quantification by the parameter p.
Thank you so much for the suggestion:-)

…he function to classification, and incorporate class_dis example into plot_toy_classification
@msyamamoto
Copy link
Contributor Author

Do not forget to add tests for your new function, for two and three classes.

I added two tests at the end of test_classification.py. Please confirm them.

@agramfort
Copy link
Member

@msyamamoto pushed a short commit here. Please have a look

@qbarthelemy thoughts?

@msyamamoto
Copy link
Contributor Author

@agramfort Wow! I can learn so many things from your commit!! Thank you so much for the speedy revision!

Copy link
Member

@qbarthelemy qbarthelemy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not forget to complete whatsnew file.

pyriemann/classification.py Outdated Show resolved Hide resolved
pyriemann/classification.py Outdated Show resolved Hide resolved
pyriemann/classification.py Outdated Show resolved Hide resolved
Copy link
Member

@sylvchev sylvchev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example is really nice!

pyriemann/classification.py Outdated Show resolved Hide resolved
pyriemann/classification.py Outdated Show resolved Hide resolved
pyriemann/classification.py Outdated Show resolved Hide resolved
pyriemann/classification.py Outdated Show resolved Hide resolved
pyriemann/classification.py Outdated Show resolved Hide resolved
Copy link
Member

@agramfort agramfort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing more to add on my end

thx @msyamamoto 🙏

pyriemann/classification.py Outdated Show resolved Hide resolved
pyriemann/classification.py Outdated Show resolved Hide resolved

def class_distinctiveness(X, y, nume_denomi=False):
"""Measure class separability between classes on a manifold.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the article, a power of 2 was lost bewteen Eq(4) and Eq(5), giving a mean absolute deviation instead of a variance.

I suggest to add an argument $p$:
$$\mathrm{classDis}(A, B, p) = \frac{d \left(\bar{X}^{A}, \bar{X}^{B}\right)^p} {\frac{1}{2} \left( \sigma_{X^{A}}^p + \sigma_{X^{B}}^p \right)}$$
where
$$\sigma_{X^{K}}^p = \frac{1}{m} \sum_{i=1}^m d \left(X_i, \bar{X}^{K}\right)^p$$
When $p=1$, it gives equation from article.
When $p=2$, it really generalizes Fisher criterion, defined as the ratio of the variance between the classes to the variance within the classes.

pyriemann/classification.py Outdated Show resolved Hide resolved
pyriemann/classification.py Outdated Show resolved Hide resolved
Copy link
Member

@agramfort agramfort left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a final nitpick on my end

pyriemann/classification.py Outdated Show resolved Hide resolved
@agramfort
Copy link
Member

@qbarthelemy @sylvchev feel free to merge if happy

Copy link
Member

@qbarthelemy qbarthelemy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx @msyamamoto !
@sylvchev , some remarks?

@sylvchev
Copy link
Member

Good for me, ok to merge
Thanks @msyamamoto and kudos for your first PR!

@agramfort agramfort merged commit 56cf653 into pyRiemann:master Dec 13, 2022
@agramfort
Copy link
Member

👏 @msyamamoto 👏

@msyamamoto
Copy link
Contributor Author

Thank you so much for approving this PR! @agramfort @qbarthelemy @sylvchev
During these 11 days, I could learn so many things from you all and my coding skill was greatly improved thanks to you!
Also, it was very enjoyable to improve something together through GitHub interactions:-)
I appreciate all your detailed feedback and look forward to working on the next PR 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants