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

Dev - Symbolic dynamics HRV parameters added #1057

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from

Conversation

mrosol
Copy link

@mrosol mrosol commented Dec 12, 2024

Description

This PR aims at adding calculation of symbolic dynamics HRV parameters [1-5]

[1] Cysarz, D., Edelhäuser, F., Javorka, M., Montano, N., and Porta, A. (2018). On the relevance of symbolizing heart rate variability by means of a percentile-based coarse graining approach. Physiol. Meas. 39:105010. doi: 10.1088/1361-6579/aae302
[2] Cysarz, D., Porta, A., Montano, N., Leeuwen, P. V., Kurths, J., and Wessel, N. (2013). Quantifying heart rate dynamics using different approaches of symbolic dynamics. Eur. Phys. J. Spec. Top. 222, 487–500. doi: 10.1140/epjst/e2013-01854-7
[3] Wessel, N., Malberg, H., Bauernschmitt, R., and Kurths, J. (2007). Nonlinear methods of cardiovascular physics and their clinical applicability. Int. J. Bifurc. Chaos 17, 3325–3371. doi: 10.1142/s0218127407019093
[4] Porta, A., Tobaldini, E., Guzzetti, S., Furlan, R., Montano, N., and Gnecchi-Ruscone, T. (2007). Assessment of cardiac autonomic modulation during graded head-up tilt by symbolic analysis of heart rate variability. Am. J. Physiol. Heart Circ. Physiol. 293, H702–H708. doi: 10.1152/ajpheart.00006.2007
[5] Gąsior, J. S., Rosoł, M., Młyńczak, M., Flatt, A. A., Hoffmann, B., Baranowski, R., Werner, B. (2022). Reliability of Symbolic Analysis of Heart Rate Variability and Its Changes During Sympathetic Stimulation in Elite Modern Pentathlon Athletes: A Pilot Study. Front. Physiol. 13, doi: 10.3389/fphys.2022.829887

Proposed Changes

I added neurokit2/hrv/hrv_symdyn.py and changed the following files neurokit2/hrv/hrv.py, neurokit2/hrv/__init__.py, tests/tests_hrv.py, docs/functions/hrv.rst

Checklist

Here are some things to check before creating the PR. If you encounter any issues, do let us know :)

  • [+] I have read the CONTRIBUTING file.
  • [+] My PR is targeted at the dev branch (and not towards the master branch).
  • [+] I ran the CODE CHECKS on the files I added or modified and fixed the errors.
  • [NA] I have added the newly added features to News.rst (if applicable)

Copy link

welcome bot commented Dec 12, 2024

Thanks for opening this pull request! We'll make sure it's perfect before merging 🤗 force
Make sure to read the contributing guide. Also, if you think that your contribution is worthy of it, you can consider adding yourself to the Contributors list (feel free to ask us if you have any doubts).

@DominiqueMakowski
Copy link
Member

@Tam-Pham kind bump

@DominiqueMakowski
Copy link
Member

@Tam-Pham bump x2

@DominiqueMakowski
Copy link
Member

@mrosol thanks a lot for that very interesting paper (and sorry for the delay in reviewing it 😩)
quick question, wouldn't that symbolic dynamics approach fits under non-linear instead of its own separate "domain" ?

@mrosol
Copy link
Author

mrosol commented Feb 11, 2025

@DominiqueMakowski I thought to separate it from the code clarity perspective, not to extend the file with nonlinear parameters too much, but it might go over there as well. Do you want me to move it from hrv_symdyn.py to hrv_nonlinear.py? :)

Copy link
Member

@Tam-Pham Tam-Pham left a comment

Choose a reason for hiding this comment

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

Hi @mrosol

I'm so so so sorry for the late review. It has been a few hectic months for me.

Thank you for your contribution to the package. Symbolic dynamic metrics are indeed interesting and novel parameters for the ANS activities.

I agree that they could be placed under the non-linear domain as similar to other metrics there, they are capturing the dynamics in the signal that are distinct from the traditional statistical or frequency-based metrics. However, I'm not sure how to incorporate them into the existing function.

@mrosol I have added just 2 comments - 1 of them would need @DominiqueMakowski inputs with the naming convention. Other than that, the code looks great :) Thanks so much

A dictionary with keys corresponding to the symbolic dynamics families ('0V', '1V', '2LV', '2UV')
and values representing the normalized counts of words belonging to each family.
"""
families = {'0V': 0, '1V': 0, '2LV': 0, '2UV': 0}
Copy link
Member

Choose a reason for hiding this comment

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

Suggest making a few revisions to improve the efficiency of this function:

  1. using np.unique() instead of len(set(word)) to avoid processing one word at a time in a loop
words = np.array(words)  # Ensure input is a NumPy array
unique_counts = np.apply_along_axis(lambda w: len(np.unique(w)), 1, words) 
  1. accumulate raw count using np.sum() without looping
families = {
        '0V': np.sum(unique_counts == 1),
        '1V': np.sum(unique_counts == 2),
        '2LV': np.sum((unique_counts == 3) & ((words[:, 1] > words[:, 0]) & (words[:, 2] > words[:, 1]) |
                                             (words[:, 1] < words[:, 0]) & (words[:, 2] < words[:, 1]))),
        '2UV': np.sum((unique_counts == 3) & ~((words[:, 1] > words[:, 0]) & (words[:, 2] > words[:, 1]) |
                                               (words[:, 1] < words[:, 0]) & (words[:, 2] < words[:, 1]))),
    }
  1. calculate len(words) just once
total_words = len(words)
for key in families:
      families[key] /= total_words

* **SymDynSigma0.05_1V**: Indicates the percentage of sequences with one variation, derived using the σ method.
* **SymDynSigma0.05_2LV**: Reflects the percentage of sequences with two like variations, as quantized by the σ method.
* **SymDynSigma0.05_2UV**: Shows the percentage of sequences with two unlike variations, according to the σ method.
* **SymDynEqualPorba4_0V**: Represents the percentage of sequences with zero variation, derived using the Equal-Probability method with quantization level 4, ensuring each level has the same number of points.
Copy link
Member

Choose a reason for hiding this comment

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

Should it be "Proba" instead of "Porba"?

Anyway, in terms of naming output variables, we don't have an existing naming convention with the method inside the variable names (@DominiqueMakowski correct me if I'm wrong). Would SymDyn_EqualProb4_1V instead of SymDynEqualProb4_1V be clearer?

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

Successfully merging this pull request may close these issues.

3 participants