.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/cadence/_02_cad_evaluation.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_cadence__02_cad_evaluation.py: .. _cad_evaluation: Cadence Evaluation ================== This example shows how to apply evaluation algorithms to cadence results and thus how to rate the performance of a cadence calculation algorithm. .. GENERATED FROM PYTHON SOURCE LINES 10-17 .. code-block:: default from pprint import pprint import numpy as np import pandas as pd from mobgap.data import LabExampleDataset .. GENERATED FROM PYTHON SOURCE LINES 18-25 Example Data ------------ We load example data from the lab dataset. We will use a longer trial from an "MS" participant for this example. Additionally, we will load the reference cadence values to compare the results and evaluate the performance of the cadence calculation algorithm. To calculate the cadence, we will then use the initial contacts measured from the reference system. .. GENERATED FROM PYTHON SOURCE LINES 25-47 .. code-block:: default def load_data(): """Load example data from the lab dataset.""" lab_example_data = LabExampleDataset(reference_system="INDIP") long_trial = lab_example_data.get_subset( cohort="MS", participant_id="001", test="Test11", trial="Trial1" ) sampling_rate_hz = long_trial.sampling_rate_hz return long_trial, sampling_rate_hz def load_reference(data): """Load reference from the INDIP reference system.""" reference_gs = data.reference_parameters_.wb_list reference_ic = data.reference_parameters_relative_to_wb_.ic_list return reference_gs, reference_ic test_data, sampling_rate_hz = load_data() reference_gs, reference_ic = load_reference(test_data) .. rst-class:: sphx-glr-script-out .. code-block:: none /home/docs/checkouts/readthedocs.org/user_builds/mobgap/checkouts/v0.9.0/mobgap/data/_mobilised_matlab_loader.py:1082: UserWarning: There were multiple ICs with the same index value, but different LR labels. This is likely an issue with the reference system you should further investigate. For now, we set the `lr_label` of the stride corresponding to this IC to Nan. However, both values still remain in the IC list. return parse_reference_parameters( /home/docs/checkouts/readthedocs.org/user_builds/mobgap/checkouts/v0.9.0/mobgap/data/_mobilised_matlab_loader.py:1091: UserWarning: There were multiple ICs with the same index value, but different LR labels. This is likely an issue with the reference system you should further investigate. For now, we set the `lr_label` of the stride corresponding to this IC to Nan. However, both values still remain in the IC list. return parse_reference_parameters( .. GENERATED FROM PYTHON SOURCE LINES 48-50 From the reference data, we can see that our example data contains several gait sequences. For each gait sequence, the reference system provides an average cadence value. .. GENERATED FROM PYTHON SOURCE LINES 50-52 .. code-block:: default reference_gs[["avg_cadence_spm"]] .. raw:: html
avg_cadence_spm
wb_id
0 107.795850
1 93.396106
2 75.981133
3 92.337768
4 87.915774
5 95.365740


.. GENERATED FROM PYTHON SOURCE LINES 53-56 Furthermore, the reference data includes a list of initial contacts for each gait sequence. We will use these reference initial contacts as input for the cadence calculation algorithm, to enable evaluating the performance of the cadence calculation in isolation. .. GENERATED FROM PYTHON SOURCE LINES 56-58 .. code-block:: default reference_ic .. raw:: html
ic lr_label
wb_id step_id
0 0 0 right
1 46 left
2 110 right
3 153 left
4 217 right
... ... ... ...
5 7 518 right
8 573 left
9 664 right
10 711 left
11 750 right

93 rows × 2 columns



.. GENERATED FROM PYTHON SOURCE LINES 59-63 Applying the Cadence Calculation Algorithm ------------------------------------------ In this example, we will use the :class:`~mobgap.cadence.CadFromIc` algorithm to calculate the cadence from the reference initial contacts. .. GENERATED FROM PYTHON SOURCE LINES 63-68 .. code-block:: default from mobgap.cadence import CadFromIc cad_from_ic = CadFromIc() .. GENERATED FROM PYTHON SOURCE LINES 69-74 As this algorithm is designed to work on a single gait sequence at a time, we will iterate over the gait sequences present in the example data and calculate the cadence for each of them. This is done using the :class:`~mobgap.pipeline.GsIterator` class. How the :class:`~mobgap.pipeline.GsIterator` class works in detail together with different application examples is explained in its :ref:`dedicated example `. .. GENERATED FROM PYTHON SOURCE LINES 74-91 .. code-block:: default from mobgap.initial_contacts import refine_gs from mobgap.pipeline import GsIterator from mobgap.utils.conversions import to_body_frame iterator = GsIterator() for (gs, data), r in iterator.iterate(test_data.data_ss, reference_gs): r.ic_list = reference_ic.loc[gs.id] refined_gs, refined_ic_list = refine_gs(r.ic_list) with iterator.subregion(refined_gs) as ((_, refined_gs_data), rr): cad = cad_from_ic.clone().calculate( to_body_frame(refined_gs_data), initial_contacts=refined_ic_list, sampling_rate_hz=sampling_rate_hz, ) rr.cadence_per_sec = cad.cadence_per_sec_ .. GENERATED FROM PYTHON SOURCE LINES 92-94 The detected cadences per second for all gait sequences can then be accessed from the `results_` attribute of the `GsIterator` object. .. GENERATED FROM PYTHON SOURCE LINES 94-97 .. code-block:: default cadence_result = iterator.results_.cadence_per_sec cadence_result .. raw:: html
cadence_spm
wb_id r_gs_id sec_center_samples
0 0 1069 109.090909
1169 112.149533
1269 106.194690
1369 112.149533
1469 90.909091
... ... ... ...
5 0 21728 102.783726
21828 101.694915
21928 109.090909
22028 127.659574
22128 153.846154

69 rows × 1 columns



.. GENERATED FROM PYTHON SOURCE LINES 98-104 Comparison with Reference -------------------------- To evaluate the performance of the cadence calculation algorithm, we can compare the calculated cadence values with the reference cadence values. For this purpose, as there are is only one reference cadence value per gait sequence, we will first average the calculated cadence values per gait sequence. .. GENERATED FROM PYTHON SOURCE LINES 104-107 .. code-block:: default avg_cadence_per_gs = cadence_result.groupby("wb_id").mean() avg_cadence_per_gs .. raw:: html
cadence_spm
wb_id
0 98.129901
1 91.064415
2 68.021660
3 93.531544
4 104.407653
5 112.940841


.. GENERATED FROM PYTHON SOURCE LINES 108-111 Next, the detected and reference cadences values are concatenated into a single DataFrame. As columns, a multilevel index is used that contains the type of metric (``cadence_spm``) in the first and the source of the data (``detected`` or ``reference``) in the second level. .. GENERATED FROM PYTHON SOURCE LINES 111-120 .. code-block:: default reference_cadence = reference_gs[["avg_cadence_spm"]].rename( columns={"avg_cadence_spm": "cadence_spm"} ) combined_cad = {"detected": avg_cadence_per_gs, "reference": reference_cadence} combined_cad = pd.concat( combined_cad, axis=1, keys=combined_cad.keys() ).reorder_levels((1, 0), axis=1) combined_cad .. raw:: html
cadence_spm
detected reference
wb_id
0 98.129901 107.795850
1 91.064415 93.396106
2 68.021660 75.981133
3 93.531544 92.337768
4 104.407653 87.915774
5 112.940841 95.365740


.. GENERATED FROM PYTHON SOURCE LINES 121-137 The concatenated DataFrame can then be used to evaluate the performance of the cadence calculation algorithm. For this purpose, first, the errors between the detected and reference cadence values are calculated. Estimate Errors in cadence data +++++++++++++++++++++++++++++++ We can calculate a variety of error metrics to evaluate the performance of the cadence calculation algorithm, ranging from the simple difference between the estimated and ground truth values (simply referred to as ``error``) to its absolute value (``absolute_error``). Both can also be set in relation to the reference value (``relative_error`` and ``absolute_relative_error``). To apply these errors, we first need to build a list specifying the error functions to be applied. All the above-mentioned error functions are provided by the :class:`~mobgap.pipeline.evaluation.ErrorTransformFuncs` class. Note that you can also apply custom functions instead of the predefined ones. For more information on how to define custom error functions, see the :ref:`general example on DMO evaluation `. .. GENERATED FROM PYTHON SOURCE LINES 137-142 .. code-block:: default from mobgap.pipeline.evaluation import ErrorTransformFuncs as E errors = [("cadence_spm", [E.error, E.abs_error, E.rel_error, E.abs_rel_error])] pprint(errors) .. rst-class:: sphx-glr-script-out .. code-block:: none [('cadence_spm', [, , , ])] .. GENERATED FROM PYTHON SOURCE LINES 143-146 The error functions can be applied to the combined cadence data using the :func:`~mobgap.utils.df_operations.apply_transformations` function. The resulting DataFrame contains the error values for each gait sequence. .. GENERATED FROM PYTHON SOURCE LINES 146-151 .. code-block:: default from mobgap.utils.df_operations import apply_transformations cad_errors = apply_transformations(combined_cad, errors) cad_errors.T .. raw:: html
wb_id 0 1 2 3 4 5
cadence_spm error -9.665949 -2.331691 -7.959474 1.193776 16.491879 17.575101
abs_error 9.665949 2.331691 7.959474 1.193776 16.491879 17.575101
rel_error -0.089669 -0.024966 -0.104756 0.012928 0.187587 0.184292
abs_rel_error 0.089669 0.024966 0.104756 0.012928 0.187587 0.184292


.. GENERATED FROM PYTHON SOURCE LINES 152-154 Before we now aggregate the results, we can also combine the error metrics with the reference and detected values to have all the information in one dataframe. .. GENERATED FROM PYTHON SOURCE LINES 154-157 .. code-block:: default combined_cad_with_errors = pd.concat([combined_cad, cad_errors], axis=1) combined_cad_with_errors .. raw:: html
cadence_spm
detected reference error abs_error rel_error abs_rel_error
wb_id
0 98.129901 107.795850 -9.665949 9.665949 -0.089669 0.089669
1 91.064415 93.396106 -2.331691 2.331691 -0.024966 0.024966
2 68.021660 75.981133 -7.959474 7.959474 -0.104756 0.104756
3 93.531544 92.337768 1.193776 1.193776 0.012928 0.012928
4 104.407653 87.915774 16.491879 16.491879 0.187587 0.187587
5 112.940841 95.365740 17.575101 17.575101 0.184292 0.184292


.. GENERATED FROM PYTHON SOURCE LINES 158-172 Aggregate Errors ++++++++++++++++ Finally, the estimated errors can be aggregated to provide a summary of the performance of the cadence calculation. For this purpose, different aggregation functions can be applied to the error metrics, ranging from simple, built-in aggregations like the mean or standard deviation to more complex functions like the limits of agreement or 5th and 95th percentiles. This can be done using the :func:`~mobgap.utils.df_operations.apply_aggregations` function. Possible aggregations are provided by the :class:`~mobgap.pipeline.evaluation.CustomErrorAggregations` class. There are two ways to define such aggregations: 1. As a list of tuples in the format ``(, )`` with ```` being the key for accessing the column to evaluate, and ```` being the aggregation function(s) to apply. A valid list of aggregations could look like this: .. GENERATED FROM PYTHON SOURCE LINES 172-186 .. code-block:: default from mobgap.pipeline.evaluation import CustomErrorAggregations as A aggregations_simple = [ *( (("cadence_spm", origin), [np.mean, A.quantiles]) for origin in ["detected", "reference", "abs_error", "abs_rel_error"] ), *( (("cadence_spm", origin), [np.mean, A.loa]) for origin in ["error", "rel_error"] ), ] pprint(aggregations_simple) .. rst-class:: sphx-glr-script-out .. code-block:: none [(('cadence_spm', 'detected'), [, ]), (('cadence_spm', 'reference'), [, ]), (('cadence_spm', 'abs_error'), [, ]), (('cadence_spm', 'abs_rel_error'), [, ]), (('cadence_spm', 'error'), [, ]), (('cadence_spm', 'rel_error'), [, ])] .. GENERATED FROM PYTHON SOURCE LINES 187-194 2. As a named tuple of Type `CustomOperation` taking three values: `identifier`, `function`, and `column_name`. `identifier` is a valid loc identifier selecting one or more columns from the dataframe, `function` is the aggregation function or list of functions to apply, and `column_name` is the identifier of the resulting column in the output dataframe. This allows for more complex aggregations that require multiple columns as input, for example, the intra-class correlation coefficient (ICC). A valid aggregation list for calculating the ICC of all DMOs would look like this: .. GENERATED FROM PYTHON SOURCE LINES 194-205 .. code-block:: default from mobgap.utils.df_operations import CustomOperation aggregations_custom = [ CustomOperation( identifier="cadence_spm", function=A.icc, column_name=("cadence_spm", "all"), ) ] pprint(aggregations_custom) .. rst-class:: sphx-glr-script-out .. code-block:: none [CustomOperation(identifier='cadence_spm', function=, column_name=('cadence_spm', 'all'))] .. GENERATED FROM PYTHON SOURCE LINES 206-214 For more detailed information on the aggregation types and their usage, check out the detailed example on it in the :ref:`general example on DMO evaluation `. Both types of aggregations can be combined and applied in a single call to the :func:`~mobgap.utils.df_operations.apply_aggregations` function. This returns a pandas Series with the aggregated values for each aggregation function and origin for the metric cadence. For better readability, we sort and format the resulting dataframe. .. GENERATED FROM PYTHON SOURCE LINES 214-225 .. code-block:: default from mobgap.utils.df_operations import apply_aggregations aggregations = aggregations_simple + aggregations_custom agg_results = ( apply_aggregations(combined_cad_with_errors, aggregations) .rename_axis(index=["aggregation", "metric", "origin"]) .reorder_levels(["metric", "origin", "aggregation"]) .sort_index(level=0) .to_frame("values") ) agg_results .. raw:: html
values
metric origin aggregation
cadence_spm abs_error mean 9.202978
quantiles (1.4782545184450235, 17.304295196502732)
abs_rel_error mean 0.1007
quantiles (0.015937671449301465, 0.18676332986307062)
all icc (0.625933703835827, [-0.16, 0.94])
detected mean 94.682669
quantiles (73.7823485337994, 110.80754397719134)
error loa (-20.730997551818866, 25.83221149212917)
mean 2.550607
reference mean 92.132062
quantiles (78.96479355928136, 104.68832292084684)
rel_error loa (-0.22707473497999797, 0.2822136055400246)
mean 0.027569


.. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 2.912 seconds) **Estimated memory usage:** 9 MB .. _sphx_glr_download_auto_examples_cadence__02_cad_evaluation.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: _02_cad_evaluation.py <_02_cad_evaluation.py>` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: _02_cad_evaluation.ipynb <_02_cad_evaluation.ipynb>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_