.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/stride_segmentation/barth_dtw_custom_template.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note Click :ref:`here ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_stride_segmentation_barth_dtw_custom_template.py: .. _example_barth_custom_template: BarthDtw stride segmentation with Custom Template ================================================= This example illustrates how to use :class:`~gaitmap.stride_segmentation.BarthDtw` with your own template extracted from the data. For more information about the method in general check out the other stride segmentation examples. .. GENERATED FROM PYTHON SOURCE LINES 11-21 .. code-block:: default import matplotlib.pyplot as plt import numpy from gaitmap.utils.consts import BF_GYR from gaitmap.utils.coordinate_conversion import convert_left_foot_to_fbf, convert_to_fbf from gaitmap.utils.datatype_helper import to_dict_multi_sensor_data numpy.random.seed(0) .. GENERATED FROM PYTHON SOURCE LINES 22-27 Getting some example data -------------------------- We will use the healthy example data for this and split it into two parts. One part to extract the template and one part to apply the template to. .. GENERATED FROM PYTHON SOURCE LINES 27-42 .. code-block:: default from gaitmap.example_data import get_healthy_example_imu_data, get_healthy_example_stride_borders data = get_healthy_example_imu_data() stride_borders = get_healthy_example_stride_borders() # Until the third left strides for template generation end_idx = stride_borders["left_sensor"].loc[3, "end"] template_data = data.iloc[:end_idx] template_stride_borders = {k: v.query("end <= @end_idx") for k, v in stride_borders.items()} data = data.iloc[stride_borders["left_sensor"].loc[3, "end"] :] data.index -= data.index[0] bf_data = convert_to_fbf(data, left_like="left_", right_like="right_") sampling_rate_hz = 204.8 data.sort_index(axis=1).head(1) .. raw:: html
sensor left_sensor right_sensor
axis acc_x acc_y acc_z gyr_x gyr_y gyr_z acc_x acc_y acc_z gyr_x gyr_y gyr_z
0.0 20.562813 -8.879406 20.3201 170.247393 592.701737 -76.229602 0.466771 -2.394534 8.629266 -23.721022 -0.946682 27.104365


.. GENERATED FROM PYTHON SOURCE LINES 43-54 .. code-block:: default fig, axs = plt.subplots(nrows=2, figsize=(10, 5), sharex=True) for ax, foot in zip(axs, ["left", "right"]): ax.set_title(f"{foot} foot") convert_left_foot_to_fbf(template_data[f"{foot}_sensor"])[BF_GYR].plot(ax=ax) # Mark stride borders with vertical lines for _i, val in template_stride_borders[f"{foot}_sensor"].iterrows(): ax.axvline(x=val["end"] / sampling_rate_hz, color="k") ax.axvline(x=val["start"] / sampling_rate_hz, color="k") plt.show() .. image-sg:: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_001.png :alt: left foot, right foot :srcset: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 55-61 Creating a custom template -------------------------- Based on the stride borders in the selected data, we can create a custom template. First we need to extract the data of the individual strides. We can do that using the :func:`~gaitmap.utils.array_handling.iterate_region_data` helper. Note this helper returns a generator that yields the data of the individual strides. .. GENERATED FROM PYTHON SOURCE LINES 61-72 .. code-block:: default from gaitmap.utils.array_handling import iterate_region_data # Convert data to body frame bf_template_data = convert_to_fbf(template_data, left_like="left_", right_like="right_") # Split the data of the left and the right foot to use it independently bf_template_data_list = to_dict_multi_sensor_data(bf_template_data).values() stride_generator = iterate_region_data(bf_template_data_list, template_stride_borders.values()) next(stride_generator) .. raw:: html
acc_pa acc_ml acc_si gyr_pa gyr_ml gyr_si
1.777344 11.274402 -9.511281 2.544769 -230.918304 -453.535482 137.227046
1.782227 3.064188 -18.365435 16.386407 -173.929262 -350.815841 101.909816
1.787109 1.781809 -7.650249 18.801136 -116.628642 -245.794645 52.136681
1.791992 5.592742 -0.200467 11.978539 -11.623749 -159.589373 28.752353
1.796875 6.477555 -3.997231 -2.629139 70.124424 -76.582277 8.182470
... ... ... ... ... ... ...
2.827148 13.450953 -1.023335 -32.286751 -181.239018 -413.213103 161.817283
2.832031 14.126770 -2.840610 -30.254729 -181.967682 -418.229653 157.299426
2.836914 18.475884 -4.153438 -27.270732 -170.285445 -425.396402 156.130050
2.841797 20.513766 -5.952154 -25.865293 -160.728109 -445.249448 142.038198
2.846680 22.052187 -12.381969 -26.504490 -181.078973 -484.216405 107.371379

220 rows × 6 columns



.. GENERATED FROM PYTHON SOURCE LINES 73-74 We recreate the generator, as the next call above removed the first stride .. GENERATED FROM PYTHON SOURCE LINES 74-76 .. code-block:: default stride_generator = iterate_region_data(bf_template_data_list, template_stride_borders.values()) .. GENERATED FROM PYTHON SOURCE LINES 77-85 Interpolating the template data ------------------------------- There are multiple ways to turn the data of the individual strides into a template. The method that is implemented in gaitmap interpolates all strides to the same length and then averages the data sample by sample. To use this method we need to create an instance of the :class:`~gaitmap.stride_segmentation.InterpolatedDtwTemplate` class. .. GENERATED FROM PYTHON SOURCE LINES 85-89 .. code-block:: default from gaitmap.stride_segmentation import InterpolatedDtwTemplate template = InterpolatedDtwTemplate() # For now we do not change the arguments and keep everything as default .. GENERATED FROM PYTHON SOURCE LINES 90-92 With this template we can call `self_optimize` with our strides to create a template based on linear interpolation. The final template length will be the average length of the individual strides. .. GENERATED FROM PYTHON SOURCE LINES 92-97 .. code-block:: default template.self_optimize(stride_generator, sampling_rate_hz, columns=BF_GYR) template.get_data().plot() plt.show() .. image-sg:: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_002.png :alt: barth dtw custom template :srcset: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 98-112 As you can see, this template represents an average stride. While we could use this template as-is, usually it makes sense to normalize the template. This will result in more comparable cost values of the DTW and allows us to adjust the template for different data ranges. For that we need to provide a scaling method. The template will store the scaling method, so that we can apply the same scaling to the data. Here, we need to make a choice, if we want to apply the exact same scaling factors of the template to the data, or just the same method of scaling. To understand the difference, let's do both Same scaling factors -------------------- .. GENERATED FROM PYTHON SOURCE LINES 112-119 .. code-block:: default from gaitmap.data_transform import StandardScaler, TrainableStandardScaler template = InterpolatedDtwTemplate(scaling=TrainableStandardScaler()) stride_generator = iterate_region_data(bf_template_data_list, template_stride_borders.values()) template.self_optimize(stride_generator, sampling_rate_hz, columns=BF_GYR) .. rst-class:: sphx-glr-script-out .. code-block:: none InterpolatedDtwTemplate(data= gyr_pa gyr_ml gyr_si 0 -225.617192 -524.765957 117.965788 1 -183.727973 -441.137654 43.403129 2 -137.772901 -317.382564 12.556771 3 -42.393835 -193.704262 -51.763276 4 45.719194 -81.699326 -89.331217 .. ... ... ... 214 -216.232104 -430.958697 163.367427 215 -215.160208 -435.032678 166.323753 216 -204.476716 -443.916617 165.512217 217 -198.979137 -460.683229 153.859775 218 -217.537175 -499.283456 132.857482 [219 rows x 3 columns], interpolation_method='linear', n_samples=None, sampling_rate_hz=204.8, scaling=TrainableStandardScaler(ddof=1, mean=-2.228665883735075, std=145.51707439675124), use_cols=None) .. GENERATED FROM PYTHON SOURCE LINES 120-122 After the template is created, we can see that the data we get from `get_data` is normalized and the scaler we provided holds the mean and standard deviation of the template. .. GENERATED FROM PYTHON SOURCE LINES 122-124 .. code-block:: default template.get_data().plot() plt.show() .. image-sg:: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_003.png :alt: barth dtw custom template :srcset: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 125-127 .. code-block:: default template.scaling .. rst-class:: sphx-glr-script-out .. code-block:: none TrainableStandardScaler(ddof=1, mean=-2.228665883735075, std=145.51707439675124) .. GENERATED FROM PYTHON SOURCE LINES 128-130 We can apply the scaling to other data using the `transform_data` method. This uses exactly the same scaling factors as the template. .. GENERATED FROM PYTHON SOURCE LINES 130-133 .. code-block:: default template.transform_data(bf_data, sampling_rate_hz=sampling_rate_hz)["left_sensor"][BF_GYR].plot() plt.show() .. image-sg:: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_004.png :alt: barth dtw custom template :srcset: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 134-139 Same method, but with the same scaling factors ---------------------------------------------- Alternatively, we can use the same scaling method as the template, but let the method recalculate the scaling factors. For this, we use the non-trainable version of the scaler. This will not store the scaling factors, but will apply standard scaling on the template and the data independently. .. GENERATED FROM PYTHON SOURCE LINES 139-147 .. code-block:: default template = InterpolatedDtwTemplate(scaling=StandardScaler()) stride_generator = iterate_region_data(bf_template_data_list, template_stride_borders.values()) template.self_optimize(stride_generator, sampling_rate_hz, columns=BF_GYR) template.get_data().plot() plt.show() .. image-sg:: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_005.png :alt: barth dtw custom template :srcset: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_005.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 148-150 The template data still looks identical, but the scaled data is slightly different, as the mean and the std of the data is used instead of the template. .. GENERATED FROM PYTHON SOURCE LINES 150-153 .. code-block:: default template.transform_data(bf_data, sampling_rate_hz=sampling_rate_hz)["left_sensor"][BF_GYR].plot() plt.show() .. image-sg:: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_006.png :alt: barth dtw custom template :srcset: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_006.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 154-162 Which approach you should use depends on the application. If you expect the matching data to have the same data range as the template, it makes sense to only learn the factors once. However, if you expect the data to have a different data range, you should scale the data independently. However, this might result in issues, if the normalization/scaling method amplifies data noise. For now we will switch back to a simple scaler trained on the template data and then show how to apply the template. .. GENERATED FROM PYTHON SOURCE LINES 162-169 .. code-block:: default from gaitmap.data_transform import TrainableAbsMaxScaler template = InterpolatedDtwTemplate(scaling=TrainableAbsMaxScaler()) stride_generator = iterate_region_data(bf_template_data_list, template_stride_borders.values()) template.self_optimize(stride_generator, sampling_rate_hz, columns=BF_GYR) .. rst-class:: sphx-glr-script-out .. code-block:: none InterpolatedDtwTemplate(data= gyr_pa gyr_ml gyr_si 0 -225.617192 -524.765957 117.965788 1 -183.727973 -441.137654 43.403129 2 -137.772901 -317.382564 12.556771 3 -42.393835 -193.704262 -51.763276 4 45.719194 -81.699326 -89.331217 .. ... ... ... 214 -216.232104 -430.958697 163.367427 215 -215.160208 -435.032678 166.323753 216 -204.476716 -443.916617 165.512217 217 -198.979137 -460.683229 153.859775 218 -217.537175 -499.283456 132.857482 [219 rows x 3 columns], interpolation_method='linear', n_samples=None, sampling_rate_hz=204.8, scaling=TrainableAbsMaxScaler(data_max=524.7659568483249, out_max=1), use_cols=None) .. GENERATED FROM PYTHON SOURCE LINES 170-175 Apply the template to the data ------------------------------ Now we can apply the template to the data using the normal :class:`~gaitmap.stride_segmentation.BarthDtw` method. Note, that all Dtw methods apply the data transform internally, so we do not need to transform the data before we apply the template. .. GENERATED FROM PYTHON SOURCE LINES 175-192 .. code-block:: default from gaitmap.stride_segmentation import BarthDtw dtw = BarthDtw(template=template) dtw.segment(bf_data, sampling_rate_hz=sampling_rate_hz) fig, axs = plt.subplots(nrows=2, figsize=(10, 5), sharex=True) for ax, foot in zip(axs, ["left", "right"]): ax.set_title(f"{foot} foot") bf_data[f"{foot}_sensor"][BF_GYR].plot(ax=ax) # Mark stride borders with vertical lines for _i, val in dtw.stride_list_[f"{foot}_sensor"].iterrows(): ax.axvline(x=val["end"] / sampling_rate_hz, color="k") ax.axvline(x=val["start"] / sampling_rate_hz, color="k") plt.show() # # sphinx_gallery_thumbnail_number = 2 .. image-sg:: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_007.png :alt: left foot, right foot :srcset: /auto_examples/stride_segmentation/images/sphx_glr_barth_dtw_custom_template_007.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** ( 0 minutes 7.144 seconds) **Estimated memory usage:** 44 MB .. _sphx_glr_download_auto_examples_stride_segmentation_barth_dtw_custom_template.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: barth_dtw_custom_template.py ` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: barth_dtw_custom_template.ipynb ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_