[New] HRV: adding indices of Symbolic Dynamics #1057
Conversation
|
Thanks for opening this pull request! We'll make sure it's perfect before merging 🤗 |
|
@Tam-Pham kind bump |
|
@Tam-Pham bump x2 |
|
@mrosol thanks a lot for that very interesting paper (and sorry for the delay in reviewing it 😩) |
|
@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 |
60c3734 to
ef4d7f0
Compare
Tam-Pham
left a comment
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
Suggest making a few revisions to improve the efficiency of this function:
- using
np.unique()instead oflen(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)
- 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]))),
}
- calculate
len(words)just once
total_words = len(words)
for key in families:
families[key] /= total_words
There was a problem hiding this comment.
Thank you, @Tam-Pham, for the revision. I have implemented the suggested changes. :)
Please let me know, if there is anything else I can do to move this PR further.
There was a problem hiding this comment.
Hi @Tam-Pham, @DominiqueMakowski, is there anything more I should do to push those changes to the main branch? My colleagues and I would like to state in the paper that the symdyn HRV parameters were also calculated using Neurokit. :)
|
@mrosol thanks so much and sorry for the ridiculous delay in finally reviewing this and merging it. It's great, note that I integrated that into nonlinear file as it is where it conceptually belongs as far as I understood, and renamed the function to Thanks again! |
|
also changed the default so that it doesn't add too many indices when using the master functions. Please don't hesitate to reach out for any suggestions or further improvement :) |
|
@DominiqueMakowski Great to hear that those changes have been merged — I can already see them in the main branch. 🙂 If any additional ideas come to mind based on our ongoing research, I’ll be happy to contribute further to this project. |
We are in the process of fixing that to update it on pypi asap :) |


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.pyand changed the following filesneurokit2/hrv/hrv.py,neurokit2/hrv/__init__.py,tests/tests_hrv.py,docs/functions/hrv.rstChecklist
Here are some things to check before creating the PR. If you encounter any issues, do let us know :)