Preconfigured Mobilised Pipelines#

As part of the Mobilise-D project two separate pipelines have been developed depending on the patient characteristics. The first pipeline MobilisedPipelineHealthy (P1 in [1]) is designed for people that likely still have a somewhat normal gait pattern. In Mobilise-D, this pipeline is used for healthy controls and patients with “COPD” and “CHF”. The second pipeline MobilisedPipelineImpaired (P2 in [1]) is designed for patients with likely significantly impaired gait patterns. In Mobilise-D, this pipeline is used for patients with “PD”, “PFF” and “MS”.

In this example we will show how to use these preconfigured pipelines. If you want to understand the details of the pipelines, please refer to the step-by-step example.

Data#

For this example, we will use the provided example data. It contains data from Lab tests from MS patients and healthy controls.

from mobgap.data import LabExampleDataset

data_ha = LabExampleDataset().get_subset(cohort="HA")
data_ha

LabExampleDataset [6 groups/rows]

cohort participant_id time_measure test trial
0 HA 001 TimeMeasure1 Test5 Trial1
1 HA 001 TimeMeasure1 Test5 Trial2
2 HA 001 TimeMeasure1 Test11 Trial1
3 HA 002 TimeMeasure1 Test5 Trial1
4 HA 002 TimeMeasure1 Test5 Trial2
5 HA 002 TimeMeasure1 Test11 Trial1


data_ms = LabExampleDataset().get_subset(cohort="MS")
data_ms

LabExampleDataset [3 groups/rows]

cohort participant_id time_measure test trial
0 MS 001 TimeMeasure1 Test5 Trial1
1 MS 001 TimeMeasure1 Test5 Trial2
2 MS 001 TimeMeasure1 Test11 Trial1


Mobilised Pipeline Healthy#

We just apply the pipeline to the first long test in the data.

Now we can access the results. Note, that the pipelines contain a large number of results. Not all of them are relevant for every use case. We only show the main outputs here:

The main output are the aggregated parameters. By default, this is just a single output for each recording. It describes the overall statistics and aggregated parameters over all WBs.

wb_all__count total_walking_duration_h wb_all__duration_s__avg wb_all__duration_s__max wb_all__duration_s__var wb_all__cadence_spm__avg wb_all__stride_duration_s__avg wb_all__cadence_spm__var wb_all__stride_duration_s__var wb_10_30__count wb_10_30__walking_speed_mps__avg wb_10_30__stride_length_m__avg wb_10__count wb_10__walking_speed_mps__max wb_30__count wb_30__walking_speed_mps__avg wb_30__stride_length_m__avg wb_30__cadence_spm__avg wb_30__stride_duration_s__avg wb_30__walking_speed_mps__max wb_30__cadence_spm__max wb_30__walking_speed_mps__var wb_30__stride_length_m__var wb_60__count
all_wbs 7 0.013853 6.38 10.828 0.440279 88.934451 1.293848 0.084865 0.135207 1 0.459428 0.69982 1 0.459428 0 NaN NaN NaN NaN NaN NaN NaN NaN 0


On level below, we have the WB parameters. This is a DataFrame with the parameters per WB.

start end n_strides rule_name rule_obj duration_s stride_duration_s cadence_spm stride_length_m walking_speed_mps
wb_id
0 630 1112 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.82 1.012857 102.691989 1.090034 0.936131
1 2832 4138 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 13.06 1.305714 79.290506 0.699820 0.459428
2 4488 5198 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 7.10 1.604286 91.005498 1.073875 0.813071
3 7848 8782 11 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.34 1.253636 85.665068 0.876754 0.631986
4 9530 10168 9 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.38 1.231111 83.159936 0.866522 0.627561
5 11032 11465 5 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.33 1.306000 88.480662 0.815119 0.620042
6 13118 13602 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.84 1.343333 92.247498 1.042341 0.833641


Even more granular are the stride level parameters. They contain only the strides that are also part of a valid WB.

original_gs_id start end lr_label stride_duration_s cadence_spm stride_length_m walking_speed_mps
wb_id s_id
0 0_0 0 630 698 left 0.68 105.263158 1.233374 1.081907
0_1 0 698 760 left 0.62 105.263158 1.243141 1.090475
0_2 0 760 872 left 1.12 105.612483 1.214946 1.069092
0_3 0 815 925 right 1.10 106.067663 1.164631 1.029320
0_4 0 872 985 left 1.13 100.861834 1.085786 0.915656
0_5 0 925 1042 right 1.17 96.368564 0.974856 0.781202
0_6 0 985 1112 left 1.27 99.407066 0.713503 0.585266
1 1_0 1 2832 3055 left 2.23 86.956522 1.005420 0.728565
1_1 1 2928 2988 right 0.60 86.956522 1.085129 0.786325
1_2 1 2988 3110 right 1.22 86.956522 0.689371 0.499544
1_3 1 3055 3260 left 2.05 85.935274 0.435341 0.311788
1_4 1 3110 3178 right 0.68 86.116186 0.421702 0.302772
1_5 1 3178 3330 right 1.52 84.554919 0.449976 0.316804
1_6 1 3260 3452 left 1.92 82.061563 0.481331 0.329020
1_8 1 3452 3618 left 1.66 69.292961 0.371950 0.209207
1_9 1 3618 3755 left 1.37 74.017038 0.440306 0.271248
1_10 1 3755 3972 left 2.17 75.743429 0.875733 0.555911
1_11 1 3852 3912 right 0.60 82.758621 1.027726 0.708776
1_12 1 3912 4038 right 1.26 66.269121 1.019503 0.563226
1_14 1 4038 4082 right 0.44 63.157895 0.739817 0.389378
1_15 1 4082 4138 right 0.56 NaN 0.754171 NaN
2 2_0 2 4488 4638 left 1.50 85.764810 1.280961 0.899756
2_1 2 4552 4755 right 2.03 95.303530 1.194271 0.938438
2_2 2 4638 4812 left 1.74 94.844301 1.172414 0.926253
2_3 2 4755 5040 right 2.85 88.907556 0.954724 0.708227
2_4 2 4812 4862 left 0.50 84.507042 0.943431 0.664388
2_5 2 4862 4965 left 1.03 89.293040 0.793240 0.588234
2_7 2 5040 5198 right 1.58 98.418209 1.178080 0.966205
3 3_0 3 7848 7985 right 1.37 67.424794 0.653801 0.364439
3_1 3 7985 8228 right 2.43 83.315121 0.768357 0.533359
3_2 3 8095 8165 left 0.70 87.410370 0.789189 0.572622
3_3 3 8165 8280 left 1.15 104.699114 0.800204 0.695348
3_4 3 8228 8335 right 1.07 100.002189 0.902968 0.750353
3_5 3 8280 8398 left 1.18 95.795841 1.007100 0.801984
3_6 3 8335 8460 right 1.25 91.912397 1.078760 0.825737
3_7 3 8398 8540 left 1.42 85.391470 1.070370 0.762595
3_8 3 8460 8608 right 1.48 80.544024 1.074253 0.720774
3_10 3 8608 8680 right 0.72 75.232198 0.885730 0.563721
3_11 3 8680 8782 right 1.02 70.588235 0.613558 0.360916
4 4_0 4 9530 9725 right 1.95 90.248060 1.149926 0.864723
4_1 4 9592 9658 left 0.66 90.333457 1.147738 0.863897
4_2 4 9658 9792 left 1.34 88.942906 1.138087 0.843714
4_3 4 9725 9855 right 1.30 87.568974 1.062864 0.776760
4_4 4 9792 9932 left 1.40 85.683181 0.938176 0.671039
4_5 4 9855 10062 right 2.07 85.745647 0.750310 0.549016
4_6 4 9932 10002 left 0.70 96.000000 0.763295 0.610636
4_7 4 10002 10105 left 1.03 67.313427 0.505012 0.306335
4_9 4 10105 10168 left 0.63 56.603774 0.343294 0.161931
5 5_0 5 11032 11295 left 2.63 80.968581 0.821912 0.555925
5_1 5 11140 11218 right 0.78 80.000000 0.977882 0.651921
5_2 5 11218 11360 right 1.42 90.158730 0.854876 0.634906
5_3 5 11295 11408 left 1.13 102.795336 0.754519 0.637417
5_5 5 11408 11465 left 0.57 NaN 0.666407 NaN
6 6_0 6 13118 13295 left 1.77 95.569545 1.093746 0.871612
6_1 6 13170 13232 right 0.62 95.410138 1.021534 0.812589
6_2 6 13232 13355 right 1.23 94.060430 1.219369 0.958393
6_3 6 13295 13420 left 1.25 90.620860 1.097951 0.831229
6_4 6 13355 13492 right 1.37 85.576517 0.970224 0.694383
6_5 6 13420 13602 left 1.82 NaN 0.851224 NaN


For other results, see the documentation of the pipeline class itself.

Mobilised Pipeline Impaired#

We just apply the pipeline to the first long test in the data.

Like before we can access the results.

wb_all__count total_walking_duration_h wb_all__duration_s__avg wb_all__duration_s__max wb_all__duration_s__var wb_all__cadence_spm__avg wb_all__stride_duration_s__avg wb_all__cadence_spm__var wb_all__stride_duration_s__var wb_10_30__count wb_10_30__walking_speed_mps__avg wb_10_30__stride_length_m__avg wb_10__count wb_10__walking_speed_mps__max wb_30__count wb_30__walking_speed_mps__avg wb_30__stride_length_m__avg wb_30__cadence_spm__avg wb_30__stride_duration_s__avg wb_30__walking_speed_mps__max wb_30__cadence_spm__max wb_30__walking_speed_mps__var wb_30__stride_length_m__var wb_60__count
all_wbs 6 0.034339 22.975 30.725 0.530908 92.851218 1.228699 0.069034 0.12652 4 0.515292 0.690068 5 0.578655 1 0.566568 0.709092 94.688179 1.209388 0.566568 94.688179 NaN NaN 0


start end n_strides rule_name rule_obj duration_s stride_duration_s cadence_spm stride_length_m walking_speed_mps
wb_id
0 872 3242 30 max_break MaxBreakCriteria(consider_end_as_break=True, m... 23.70 1.263000 86.844770 0.676846 0.520119
1 3822 6047 24 max_break MaxBreakCriteria(consider_end_as_break=True, m... 22.25 1.513750 85.831971 0.637074 0.447089
2 6990 7457 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.67 1.183333 101.849109 0.313034 0.264170
3 9585 10740 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 11.55 1.059286 98.030102 0.637877 0.507249
4 11252 14800 49 max_break MaxBreakCriteria(consider_end_as_break=True, m... 35.48 1.209388 94.688179 0.709092 0.566568
5 19887 22484 32 max_break MaxBreakCriteria(consider_end_as_break=True, m... 25.97 1.143438 89.863178 0.808476 0.586712


original_gs_id start end lr_label stride_duration_s cadence_spm stride_length_m walking_speed_mps
wb_id s_id
0 0_0 0 872 982 left 1.10 61.348360 0.855402 0.442297
0_1 0 982 1062 left 0.80 92.307692 1.048622 0.806632
0_2 0 1062 1172 left 1.10 106.671707 1.168885 1.040497
0_3 0 1117 1227 right 1.10 108.108108 1.155128 1.040656
0_4 0 1172 1282 left 1.10 107.684487 1.123642 1.008525
... ... ... ... ... ... ... ... ... ...
5 5_29 5 21984 22090 right 1.06 58.386002 0.971302 0.472520
5_31 5 22090 22130 right 0.40 60.000000 0.911013 0.455507
5_32 5 22130 22227 right 0.97 68.693229 0.980077 0.568168
5_34 5 22352 22434 left 0.82 111.681643 0.603109 0.524846
5_35 5 22434 22484 left 0.50 127.659574 0.399220 0.424702

155 rows × 8 columns



That’s it. As you can see, it is super simple to run the preconfigured pipelines on your data, if they are structured as a valid gait dataset.

However, when running a larger study, you might want to process all data at once. Then it become “inconvenient” to run the pipeline for each recording separately manually.

Luckily, it is relatively easy to implement a loop that runs the pipeline for each recording. We can even use MobilisedPipelineUniversal to automatically process all MS participants with the impaired pipeline and all HA participants with the healthy pipeline.

The meta-pipeline uses the recommended_cohorts parameter of the respective pipeline to determine which pipeline to use.

MobilisedPipelineHealthy().recommended_cohorts
('HA', 'COPD', 'CHF')
MobilisedPipelineImpaired().recommended_cohorts
('PD', 'MS', 'PFF')

So we can simply loop over all the data and run the meta-pipeline. We add a little bit of logic to deal with trials that for which we might not detect a valid WB. Then we aggregate the results.

For the aggreate_parameters we modify the index, so that we have rows with NaNs for the trials that did not have any valid WBs.

import pandas as pd
from tqdm.auto import tqdm

per_wb_paras = {}
aggregated_paras = {}

for trial in tqdm(LabExampleDataset()):
    pipe = meta_pipeline.clone().safe_run(trial)
    if not (per_wb := pipe.per_wb_parameters_).empty:
        per_wb_paras[trial.group_label] = per_wb
    if not (agg := pipe.aggregated_parameters_).empty:
        aggregated_paras[trial.group_label] = agg

per_wb_paras = pd.concat(per_wb_paras)
aggregated_paras = (
    pd.concat(aggregated_paras)
    .reset_index(-1, drop=True)
    .rename_axis(LabExampleDataset().index.columns)
    .reindex(pd.MultiIndex.from_tuples(LabExampleDataset().group_labels))
)
  0%|          | 0/9 [00:00<?, ?it/s]
 11%|█         | 1/9 [00:00<00:06,  1.15it/s]
 22%|██▏       | 2/9 [00:01<00:05,  1.23it/s]
 33%|███▎      | 3/9 [00:03<00:07,  1.24s/it]
 44%|████▍     | 4/9 [00:04<00:05,  1.07s/it]
 56%|█████▌    | 5/9 [00:04<00:03,  1.05it/s]
 67%|██████▋   | 6/9 [00:06<00:03,  1.16s/it]
 78%|███████▊  | 7/9 [00:07<00:02,  1.06s/it]
 89%|████████▉ | 8/9 [00:08<00:00,  1.04it/s]
100%|██████████| 9/9 [00:09<00:00,  1.22s/it]
100%|██████████| 9/9 [00:09<00:00,  1.10s/it]

And now we can simply access the results.

First the per WB parameters. Each row represents a WB and the multi-index tells us from which participant and which test it is.

start end n_strides rule_name rule_obj duration_s stride_duration_s cadence_spm stride_length_m walking_speed_mps
wb_id
HA 001 TimeMeasure1 Test5 Trial1 0 498 1115 9 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.17 1.018889 97.899883 1.117954 0.913728
Trial2 0 288 978 10 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.90 1.235000 98.030680 1.135347 0.940588
Test11 Trial1 0 630 1112 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.82 1.012857 102.691989 1.090034 0.936131
1 2832 4138 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 13.06 1.305714 79.290506 0.699820 0.459428
2 4488 5198 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 7.10 1.604286 91.005498 1.073875 0.813071
3 7848 8782 11 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.34 1.253636 85.665068 0.876754 0.631986
4 9530 10168 9 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.38 1.231111 83.159936 0.866522 0.627561
5 11032 11465 5 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.33 1.306000 88.480662 0.815119 0.620042
6 13118 13602 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.84 1.343333 92.247498 1.042341 0.833641
002 TimeMeasure1 Test5 Trial1 0 280 738 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.58 1.241667 91.804548 1.336870 1.086709
Trial2 0 115 592 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.77 1.203333 89.651780 1.526244 1.140765
Test11 Trial1 0 480 1138 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.58 1.501429 79.867370 0.876918 0.606178
1 2458 3992 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 15.34 1.120714 79.699313 0.780502 0.531853
2 5828 7165 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 13.37 1.531429 79.649525 0.907287 0.606492
3 7422 7892 5 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.70 1.224000 68.876437 1.017490 0.574664
4 15088 15520 4 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.32 1.212500 81.999762 0.605725 0.418552
MS 001 TimeMeasure1 Test5 Trial1 0 570 1242 11 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.72 1.074545 103.020719 1.029385 0.889534
Trial2 0 313 1047 12 max_break MaxBreakCriteria(consider_end_as_break=True, m... 7.34 1.121667 104.153676 0.929266 0.848564
Test11 Trial1 0 872 3242 30 max_break MaxBreakCriteria(consider_end_as_break=True, m... 23.70 1.263000 86.844770 0.676846 0.520119
1 3822 6047 24 max_break MaxBreakCriteria(consider_end_as_break=True, m... 22.25 1.513750 85.831971 0.637074 0.447089
2 6990 7457 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.67 1.183333 101.849109 0.313034 0.264170
3 9585 10740 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 11.55 1.059286 98.030102 0.637877 0.507249
4 11252 14800 49 max_break MaxBreakCriteria(consider_end_as_break=True, m... 35.48 1.209388 94.688179 0.709092 0.566568
5 19887 22484 32 max_break MaxBreakCriteria(consider_end_as_break=True, m... 25.97 1.143438 89.863178 0.808476 0.586712


And the aggregated parameters. Note, that many values are NaN, because only a single WB was detected per trial. So we can not calculate the standard deviation or other statistics. To learn more about what the different aggregated values mean, check MobilisedAggregator.

aggregated_paras


# Modifying Parameters
# -------------------
# Both pipelines are basically the same, but the algorithms used for certain steps are different.
# Both just reimplement :class:`~mobgap.pipeline.BaseMobilisedPipeline` with the respective algorithms as default
# parameters.
# So we can easily modify the parameters of the pipeline either using the ``set_params`` method or by passing different
# parameters/algorithms to the constructor.
#
# .. warning:: As part of Mobilise-D we only validated the pipelines with their default values in exactly the cohorts we
#              recommend them for.
#              If you change the parameters, or use them in a different cohort, we ask you to not call this approach
#              "the Mobilised Pipeline" anymore, when communicating your results.
#
# Starting simple, let's say we simply don't want to filter and aggregate the final DMOs.
# We just set the respective parameters to None.
from mobgap.pipeline import MobilisedPipelineHealthy

pipe_no_agg = MobilisedPipelineHealthy(
    dmo_thresholds=None, dmo_aggregation=None
)
pipe_no_agg.safe_run(long_test_ha)
MobilisedPipelineHealthy(cadence_calculation=CadFromIcDetector(ic_detector=IcdShinImproved(axis='norm'), max_interpolation_gap_s=3, silence_ic_warning=True, step_time_smoothing=HampelFilter(half_window_size=2, n_sigmas=3.0)), dmo_aggregation=None, dmo_thresholds=None, gait_sequence_detection=GsdIluz(acc_v_standing_threshold=4.903325, allowed_acc_v_change_per_window=0.15, allowed_steps_per_s=(0.5, 3), mean_activity_threshold=-0.980665, min_gsd_duration_s=5, pre_filter=FirFilter(cutoff_freq_hz=(0.5, 3), filter_type='bandpass', order=200, window='hamming', zero_phase=True), sin_template_freq_hz=2, std_activity_threshold=0.0980665, step_detection_thresholds=(3.92266, 14.709975), window_length_s=3, window_overlap=0.5), initial_contact_detection=IcdIonescu(cwt_width=9.0, pre_filter=EpflDedriftedGaitFilter(zero_phase=True)), laterality_classification=LrcUllrich(clf_pipe=Pipeline(steps=[('scaler_old', MinMaxScaler()),
                ('clf_old', SVC(C=0.1, kernel='linear'))]), smoothing_filter=ButterworthFilter(cutoff_freq_hz=(0.5, 2), filter_type='bandpass', order=4, zero_phase=True)), recommended_cohorts=('HA', 'COPD', 'CHF'), stride_length_calculation=SlZijlstra(acc_smoothing=ButterworthFilter(cutoff_freq_hz=0.1, filter_type='highpass', order=4, zero_phase=True), max_interpolation_gap_s=3, orientation_method=None, speed_smoothing=ButterworthFilter(cutoff_freq_hz=1, filter_type='highpass', order=4, zero_phase=True), step_length_scaling_factor=1.14675, step_length_smoothing=HampelFilter(half_window_size=2, n_sigmas=3.0)), stride_selection=StrideSelection(incompatible_rules='warn', rules=[('stride_duration_thres', IntervalDurationCriteria(inclusive=(False, True), max_duration_s=3.0, min_duration_s=0.2)), ('stride_length_thres', IntervalParameterCriteria(inclusive=(False, True), lower_threshold=0.15, parameter='stride_length_m', upper_threshold=None))]), turn_detection=TdElGohary(allowed_turn_angle_deg=(45, inf), allowed_turn_duration_s=(0.5, 10), lower_threshold_velocity_dps=5, min_gap_between_turns_s=0.05, min_peak_angle_velocity_dps=15, orientation_estimation=None, smoothing_filter=ButterworthFilter(cutoff_freq_hz=0.5, filter_type='lowpass', order=4, zero_phase=True)), walking_speed_calculation=WsNaive(), wba=WbAssembly(rules=[('min_strides', NStridesCriteria(min_strides=4, min_strides_left=3, min_strides_right=3)), ('max_break', MaxBreakCriteria(consider_end_as_break=True, max_break_s=3, remove_last_ic=False))]))

Now, the aggregated parameters are empty.

pipe_no_agg.aggregated_parameters_

And the per WB parameters are still there.

start end n_strides rule_name rule_obj duration_s stride_duration_s cadence_spm stride_length_m walking_speed_mps
wb_id
0 630 1112 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.82 1.012857 102.691989 1.090034 0.936131
1 2832 4138 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 13.06 1.305714 79.290506 0.699820 0.459428
2 4488 5198 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 7.10 1.604286 91.005498 1.073875 0.813071
3 7848 8782 11 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.34 1.253636 85.665068 0.876754 0.631986
4 9530 10168 9 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.38 1.231111 83.159936 0.866522 0.627561
5 11032 11465 5 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.33 1.306000 88.480662 0.815119 0.620042
6 13118 13602 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.84 1.343333 92.247498 1.042341 0.833641


If you want to change the algorithm used for a certain step, you can simply pass a different algorithm to the constructor. For example, let’s say you want to use the Adaptive Ionescu GSD algorithm instead of the GSDIluz (which is the default for the healthy pipeline).

For the sake of this example, we will also modify the default parameters of the algorithm.

from mobgap.gait_sequences import GsdAdaptiveIonescu

pipe_adaptive_gsd = MobilisedPipelineHealthy(
    gait_sequence_detection=GsdAdaptiveIonescu(min_n_steps=3)
)
pipe_adaptive_gsd.safe_run(long_test_ha)
MobilisedPipelineHealthy(cadence_calculation=CadFromIcDetector(ic_detector=IcdShinImproved(axis='norm'), max_interpolation_gap_s=3, silence_ic_warning=True, step_time_smoothing=HampelFilter(half_window_size=2, n_sigmas=3.0)), dmo_aggregation=MobilisedAggregator(groupby=None, unique_wb_id_column='wb_id', use_original_names=False), dmo_thresholds=condition                free_living              ...     global
threshold_type                   min         max  ...        min      max
dmo               cohort                          ...
cadence_spm       CHF      40.594770  167.942930  ...  40.000000  172.900
                  COPD     38.880484  151.558718  ...  40.000000  172.900
                  HA       35.751898  156.946955  ...  40.000000  172.900
                  MS       38.443211  155.394496  ...  40.000000  172.900
                  PD       40.957969  142.121947  ...  40.000000  172.900
                  PFF      42.191719  157.613665  ...  40.000000  172.900
walking_speed_mps CHF       0.112478    1.757103  ...   0.081515    2.220
                  COPD      0.090731    1.641773  ...   0.081515    2.220
                  HA        0.097413    1.965728  ...   0.081515    2.220
                  MS        0.085918    1.920262  ...   0.081515    2.220
                  PD        0.081515    1.735348  ...   0.081515    2.220
                  PFF       0.104547    1.553186  ...   0.081515    2.220
stride_length_m   CHF       0.185308    2.166646  ...   0.150523    2.190
                  COPD      0.176403    1.711645  ...   0.150523    2.190
                  HA        0.155126    2.024694  ...   0.150523    2.190
                  MS        0.191099    1.940537  ...   0.150523    2.190
                  PD        0.150523    1.982926  ...   0.150523    2.190
                  PFF       0.206787    1.697251  ...   0.150523    2.190
stride_duration_s CHF       0.702000    3.030857  ...   0.460000    3.000
                  COPD      0.770000    3.000000  ...   0.460000    3.000
                  HA        0.735435    3.254400  ...   0.460000    3.000
                  MS        0.775597    3.057750  ...   0.460000    3.000
                  PD        0.836253    2.928000  ...   0.460000    3.000
                  PFF       0.744000    2.769000  ...   0.460000    3.000
step_duration_s   CHF       0.376000    1.504500  ...   0.140000    2.124
                  COPD      0.390400    1.788000  ...   0.140000    2.124
                  HA        0.367972    1.730400  ...   0.140000    2.124
                  MS        0.388084    1.905000  ...   0.140000    2.124
                  PD        0.417216    1.605600  ...   0.140000    2.124
                  PFF       0.371429    2.124000  ...   0.140000    2.124

[30 rows x 8 columns], gait_sequence_detection=GsdAdaptiveIonescu(active_signal_fallback_threshold=0.15, max_gap_s=3.5, min_n_steps=3, min_step_margin_s=1.5, padding=0.75), initial_contact_detection=IcdIonescu(cwt_width=9.0, pre_filter=EpflDedriftedGaitFilter(zero_phase=True)), laterality_classification=LrcUllrich(clf_pipe=Pipeline(steps=[('scaler_old', MinMaxScaler()),
                ('clf_old', SVC(C=0.1, kernel='linear'))]), smoothing_filter=ButterworthFilter(cutoff_freq_hz=(0.5, 2), filter_type='bandpass', order=4, zero_phase=True)), recommended_cohorts=('HA', 'COPD', 'CHF'), stride_length_calculation=SlZijlstra(acc_smoothing=ButterworthFilter(cutoff_freq_hz=0.1, filter_type='highpass', order=4, zero_phase=True), max_interpolation_gap_s=3, orientation_method=None, speed_smoothing=ButterworthFilter(cutoff_freq_hz=1, filter_type='highpass', order=4, zero_phase=True), step_length_scaling_factor=1.14675, step_length_smoothing=HampelFilter(half_window_size=2, n_sigmas=3.0)), stride_selection=StrideSelection(incompatible_rules='warn', rules=[('stride_duration_thres', IntervalDurationCriteria(inclusive=(False, True), max_duration_s=3.0, min_duration_s=0.2)), ('stride_length_thres', IntervalParameterCriteria(inclusive=(False, True), lower_threshold=0.15, parameter='stride_length_m', upper_threshold=None))]), turn_detection=TdElGohary(allowed_turn_angle_deg=(45, inf), allowed_turn_duration_s=(0.5, 10), lower_threshold_velocity_dps=5, min_gap_between_turns_s=0.05, min_peak_angle_velocity_dps=15, orientation_estimation=None, smoothing_filter=ButterworthFilter(cutoff_freq_hz=0.5, filter_type='lowpass', order=4, zero_phase=True)), walking_speed_calculation=WsNaive(), wba=WbAssembly(rules=[('min_strides', NStridesCriteria(min_strides=4, min_strides_left=3, min_strides_right=3)), ('max_break', MaxBreakCriteria(consider_end_as_break=True, max_break_s=3, remove_last_ic=False))]))

This works as before and all parameters of the pipeline are still available.

wb_all__count total_walking_duration_h wb_all__duration_s__avg wb_all__duration_s__max wb_all__duration_s__var wb_all__cadence_spm__avg wb_all__stride_duration_s__avg wb_all__cadence_spm__var wb_all__stride_duration_s__var wb_10_30__count wb_10_30__walking_speed_mps__avg wb_10_30__stride_length_m__avg wb_10__count wb_10__walking_speed_mps__max wb_30__count wb_30__walking_speed_mps__avg wb_30__stride_length_m__avg wb_30__cadence_spm__avg wb_30__stride_duration_s__avg wb_30__walking_speed_mps__max wb_30__cadence_spm__max wb_30__walking_speed_mps__var wb_30__stride_length_m__var wb_60__count
all_wbs 6 0.014753 7.245 15.335 0.615597 91.7224 1.143603 0.058541 0.150406 2 0.774082 1.05734 2 0.790859 0 NaN NaN NaN NaN NaN NaN NaN NaN 0


start end n_strides rule_name rule_obj duration_s stride_duration_s cadence_spm stride_length_m walking_speed_mps
wb_id
0 533 1045 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 5.12 0.974286 98.374985 1.056240 0.890507
1 3853 5300 18 max_break MaxBreakCriteria(consider_end_as_break=True, m... 14.47 1.355000 86.077669 1.055951 0.753111
2 7740 8677 10 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.37 1.033000 91.138330 0.957593 0.720574
3 9532 10005 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.73 1.226667 88.473947 1.042119 0.770181
4 11142 11464 4 max_break MaxBreakCriteria(consider_end_as_break=True, m... 3.22 0.970000 98.290233 0.833506 0.663899
5 11982 13602 15 max_break MaxBreakCriteria(consider_end_as_break=True, m... 16.20 1.302667 87.979239 1.058729 0.795053


When you are planning to modify many algorithms, we would recommend to not use the specific pipeline classes anymore, to avoid the association (is it really still the Healthy pipeline if you change all algorithms?). In this case, we recommend the un-configured GenericMobilisedPipeline. This class is also used as the base class for the preconfigured pipelines. It has no algorithms set by default, so you have to set all algorithms yourself. See the end of the step-by-step example for a demonstration.

If you want to reuse some of the defaults of the preconfigured pipelines, you can still use the PreconfiguredParameters. For example, we could get the same pipeline as before like this:

from mobgap.pipeline import GenericMobilisedPipeline

pipe_custom = GenericMobilisedPipeline(
    **dict(
        GenericMobilisedPipeline.PredefinedParameters.regular_walking,
        gait_sequence_detection=GsdAdaptiveIonescu(min_n_steps=3),
    )
)
pipe_adaptive_gsd.safe_run(long_test_ha)
MobilisedPipelineHealthy(cadence_calculation=CadFromIcDetector(ic_detector=IcdShinImproved(axis='norm'), max_interpolation_gap_s=3, silence_ic_warning=True, step_time_smoothing=HampelFilter(half_window_size=2, n_sigmas=3.0)), dmo_aggregation=MobilisedAggregator(groupby=None, unique_wb_id_column='wb_id', use_original_names=False), dmo_thresholds=condition                free_living              ...     global
threshold_type                   min         max  ...        min      max
dmo               cohort                          ...
cadence_spm       CHF      40.594770  167.942930  ...  40.000000  172.900
                  COPD     38.880484  151.558718  ...  40.000000  172.900
                  HA       35.751898  156.946955  ...  40.000000  172.900
                  MS       38.443211  155.394496  ...  40.000000  172.900
                  PD       40.957969  142.121947  ...  40.000000  172.900
                  PFF      42.191719  157.613665  ...  40.000000  172.900
walking_speed_mps CHF       0.112478    1.757103  ...   0.081515    2.220
                  COPD      0.090731    1.641773  ...   0.081515    2.220
                  HA        0.097413    1.965728  ...   0.081515    2.220
                  MS        0.085918    1.920262  ...   0.081515    2.220
                  PD        0.081515    1.735348  ...   0.081515    2.220
                  PFF       0.104547    1.553186  ...   0.081515    2.220
stride_length_m   CHF       0.185308    2.166646  ...   0.150523    2.190
                  COPD      0.176403    1.711645  ...   0.150523    2.190
                  HA        0.155126    2.024694  ...   0.150523    2.190
                  MS        0.191099    1.940537  ...   0.150523    2.190
                  PD        0.150523    1.982926  ...   0.150523    2.190
                  PFF       0.206787    1.697251  ...   0.150523    2.190
stride_duration_s CHF       0.702000    3.030857  ...   0.460000    3.000
                  COPD      0.770000    3.000000  ...   0.460000    3.000
                  HA        0.735435    3.254400  ...   0.460000    3.000
                  MS        0.775597    3.057750  ...   0.460000    3.000
                  PD        0.836253    2.928000  ...   0.460000    3.000
                  PFF       0.744000    2.769000  ...   0.460000    3.000
step_duration_s   CHF       0.376000    1.504500  ...   0.140000    2.124
                  COPD      0.390400    1.788000  ...   0.140000    2.124
                  HA        0.367972    1.730400  ...   0.140000    2.124
                  MS        0.388084    1.905000  ...   0.140000    2.124
                  PD        0.417216    1.605600  ...   0.140000    2.124
                  PFF       0.371429    2.124000  ...   0.140000    2.124

[30 rows x 8 columns], gait_sequence_detection=GsdAdaptiveIonescu(active_signal_fallback_threshold=0.15, max_gap_s=3.5, min_n_steps=3, min_step_margin_s=1.5, padding=0.75), initial_contact_detection=IcdIonescu(cwt_width=9.0, pre_filter=EpflDedriftedGaitFilter(zero_phase=True)), laterality_classification=LrcUllrich(clf_pipe=Pipeline(steps=[('scaler_old', MinMaxScaler()),
                ('clf_old', SVC(C=0.1, kernel='linear'))]), smoothing_filter=ButterworthFilter(cutoff_freq_hz=(0.5, 2), filter_type='bandpass', order=4, zero_phase=True)), recommended_cohorts=('HA', 'COPD', 'CHF'), stride_length_calculation=SlZijlstra(acc_smoothing=ButterworthFilter(cutoff_freq_hz=0.1, filter_type='highpass', order=4, zero_phase=True), max_interpolation_gap_s=3, orientation_method=None, speed_smoothing=ButterworthFilter(cutoff_freq_hz=1, filter_type='highpass', order=4, zero_phase=True), step_length_scaling_factor=1.14675, step_length_smoothing=HampelFilter(half_window_size=2, n_sigmas=3.0)), stride_selection=StrideSelection(incompatible_rules='warn', rules=[('stride_duration_thres', IntervalDurationCriteria(inclusive=(False, True), max_duration_s=3.0, min_duration_s=0.2)), ('stride_length_thres', IntervalParameterCriteria(inclusive=(False, True), lower_threshold=0.15, parameter='stride_length_m', upper_threshold=None))]), turn_detection=TdElGohary(allowed_turn_angle_deg=(45, inf), allowed_turn_duration_s=(0.5, 10), lower_threshold_velocity_dps=5, min_gap_between_turns_s=0.05, min_peak_angle_velocity_dps=15, orientation_estimation=None, smoothing_filter=ButterworthFilter(cutoff_freq_hz=0.5, filter_type='lowpass', order=4, zero_phase=True)), walking_speed_calculation=WsNaive(), wba=WbAssembly(rules=[('min_strides', NStridesCriteria(min_strides=4, min_strides_left=3, min_strides_right=3)), ('max_break', MaxBreakCriteria(consider_end_as_break=True, max_break_s=3, remove_last_ic=False))]))
wb_all__count total_walking_duration_h wb_all__duration_s__avg wb_all__duration_s__max wb_all__duration_s__var wb_all__cadence_spm__avg wb_all__stride_duration_s__avg wb_all__cadence_spm__var wb_all__stride_duration_s__var wb_10_30__count wb_10_30__walking_speed_mps__avg wb_10_30__stride_length_m__avg wb_10__count wb_10__walking_speed_mps__max wb_30__count wb_30__walking_speed_mps__avg wb_30__stride_length_m__avg wb_30__cadence_spm__avg wb_30__stride_duration_s__avg wb_30__walking_speed_mps__max wb_30__cadence_spm__max wb_30__walking_speed_mps__var wb_30__stride_length_m__var wb_60__count
all_wbs 6 0.014753 7.245 15.335 0.615597 91.7224 1.143603 0.058541 0.150406 2 0.774082 1.05734 2 0.790859 0 NaN NaN NaN NaN NaN NaN NaN NaN 0


start end n_strides rule_name rule_obj duration_s stride_duration_s cadence_spm stride_length_m walking_speed_mps
wb_id
0 533 1045 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 5.12 0.974286 98.374985 1.056240 0.890507
1 3853 5300 18 max_break MaxBreakCriteria(consider_end_as_break=True, m... 14.47 1.355000 86.077669 1.055951 0.753111
2 7740 8677 10 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.37 1.033000 91.138330 0.957593 0.720574
3 9532 10005 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.73 1.226667 88.473947 1.042119 0.770181
4 11142 11464 4 max_break MaxBreakCriteria(consider_end_as_break=True, m... 3.22 0.970000 98.290233 0.833506 0.663899
5 11982 13602 15 max_break MaxBreakCriteria(consider_end_as_break=True, m... 16.20 1.302667 87.979239 1.058729 0.795053


On the other end, if you are only planning to change a single sub-parameter of a pipeline, it might be easier to use the set_params method, instead of passing all parameters to the constructor.

We show the extreme example of this here, by using the Universal-Pipeline as starting point and changing the filter order of the pre-processing filter of the GSD algorithm of the healthy pipeline used internally in the MetaPipeline.

Note

The MobilisedPipelineUniversal is a special case, as it makes use of a tpcp feature called composite_params. This allows us to target the pipelines__healthy parameters, even tough pipelines is not an object, but a list of tuples. Learn more about this feature in the tpcp documentation.

from mobgap.pipeline import MobilisedPipelineUniversal

meta_pipeline_modified = MobilisedPipelineUniversal().set_params(
    pipelines__healthy__gait_sequence_detection__pre_filter__order=50
)

This parameter name is a bit long, but it demonstrates that it is possible to change even deeply nested parameters. This might be in particular useful, when you want to run approaches like GridSearch.

The algorithm works as before (note we don’t expect any change in output for this parameter change).

wb_all__count total_walking_duration_h wb_all__duration_s__avg wb_all__duration_s__max wb_all__duration_s__var wb_all__cadence_spm__avg wb_all__stride_duration_s__avg wb_all__cadence_spm__var wb_all__stride_duration_s__var wb_10_30__count wb_10_30__walking_speed_mps__avg wb_10_30__stride_length_m__avg wb_10__count wb_10__walking_speed_mps__max wb_30__count wb_30__walking_speed_mps__avg wb_30__stride_length_m__avg wb_30__cadence_spm__avg wb_30__stride_duration_s__avg wb_30__walking_speed_mps__max wb_30__cadence_spm__max wb_30__walking_speed_mps__var wb_30__stride_length_m__var wb_60__count
all_wbs 7 0.013853 6.38 10.828 0.440279 88.934451 1.293848 0.084865 0.135207 1 0.459428 0.69982 1 0.459428 0 NaN NaN NaN NaN NaN NaN NaN NaN 0


Total running time of the script: (0 minutes 29.127 seconds)

Estimated memory usage: 17 MB

Gallery generated by Sphinx-Gallery