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.45935 0.699701 1 0.45935 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.089851 0.935974
1 2832 4138 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 13.06 1.305714 79.290506 0.699701 0.459350
2 4488 5198 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 7.10 1.604286 91.005498 1.073694 0.812935
3 7848 8782 11 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.34 1.253636 85.665068 0.876606 0.631880
4 9530 10168 9 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.38 1.231111 83.159936 0.866376 0.627456
5 11032 11465 5 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.33 1.306000 88.480662 0.814981 0.619937
6 13118 13602 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.84 1.343333 92.247498 1.042166 0.833501


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.233167 1.081726
0_1 0 698 760 left 0.62 105.263158 1.242933 1.090292
0_2 0 760 872 left 1.12 105.612483 1.214743 1.068913
0_3 0 815 925 right 1.10 106.067663 1.164436 1.029147
0_4 0 872 985 left 1.13 100.861834 1.085603 0.915503
0_5 0 925 1042 right 1.17 96.368564 0.974691 0.781070
0_6 0 985 1112 left 1.27 99.407066 0.713383 0.585167
1 1_0 1 2832 3055 left 2.23 86.956522 1.005251 0.728442
1_1 1 2928 2988 right 0.60 86.956522 1.084947 0.786193
1_2 1 2988 3110 right 1.22 86.956522 0.689254 0.499460
1_3 1 3055 3260 left 2.05 85.935274 0.435267 0.311735
1_4 1 3110 3178 right 0.68 86.116186 0.421630 0.302720
1_5 1 3178 3330 right 1.52 84.554919 0.449900 0.316750
1_6 1 3260 3452 left 1.92 82.061563 0.481249 0.328964
1_8 1 3452 3618 left 1.66 69.292961 0.371887 0.209171
1_9 1 3618 3755 left 1.37 74.017038 0.440231 0.271202
1_10 1 3755 3972 left 2.17 75.743429 0.875586 0.555817
1_11 1 3852 3912 right 0.60 82.758621 1.027553 0.708657
1_12 1 3912 4038 right 1.26 66.269121 1.019332 0.563132
1_14 1 4038 4082 right 0.44 63.157895 0.739692 0.389312
1_15 1 4082 4138 right 0.56 NaN 0.754043 NaN
2 2_0 2 4488 4638 left 1.50 85.764810 1.280748 0.899606
2_1 2 4552 4755 right 2.03 95.303530 1.194072 0.938281
2_2 2 4638 4812 left 1.74 94.844301 1.172218 0.926098
2_3 2 4755 5040 right 2.85 88.907556 0.954563 0.708107
2_4 2 4812 4862 left 0.50 84.507042 0.943272 0.664276
2_5 2 4862 4965 left 1.03 89.293040 0.793105 0.588134
2_7 2 5040 5198 right 1.58 98.418209 1.177883 0.966043
3 3_0 3 7848 7985 right 1.37 67.424794 0.653690 0.364378
3_1 3 7985 8228 right 2.43 83.315121 0.768227 0.533268
3_2 3 8095 8165 left 0.70 87.410370 0.789055 0.572525
3_3 3 8165 8280 left 1.15 104.699114 0.800069 0.695230
3_4 3 8228 8335 right 1.07 100.002189 0.902816 0.750226
3_5 3 8280 8398 left 1.18 95.795841 1.006931 0.801849
3_6 3 8335 8460 right 1.25 91.912397 1.078579 0.825598
3_7 3 8398 8540 left 1.42 85.391470 1.070190 0.762467
3_8 3 8460 8608 right 1.48 80.544024 1.074073 0.720653
3_10 3 8608 8680 right 0.72 75.232198 0.885580 0.563626
3_11 3 8680 8782 right 1.02 70.588235 0.613453 0.360855
4 4_0 4 9530 9725 right 1.95 90.248060 1.149733 0.864578
4_1 4 9592 9658 left 0.66 90.333457 1.147545 0.863752
4_2 4 9658 9792 left 1.34 88.942906 1.137896 0.843573
4_3 4 9725 9855 right 1.30 87.568974 1.062686 0.776630
4_4 4 9792 9932 left 1.40 85.683181 0.938018 0.670926
4_5 4 9855 10062 right 2.07 85.745647 0.750183 0.548923
4_6 4 9932 10002 left 0.70 96.000000 0.763166 0.610533
4_7 4 10002 10105 left 1.03 67.313427 0.504927 0.306283
4_9 4 10105 10168 left 0.63 56.603774 0.343235 0.161903
5 5_0 5 11032 11295 left 2.63 80.968581 0.821773 0.555831
5_1 5 11140 11218 right 0.78 80.000000 0.977717 0.651811
5_2 5 11218 11360 right 1.42 90.158730 0.854732 0.634798
5_3 5 11295 11408 left 1.13 102.795336 0.754391 0.637309
5_5 5 11408 11465 left 0.57 NaN 0.666294 NaN
6 6_0 6 13118 13295 left 1.77 95.569545 1.093563 0.871466
6_1 6 13170 13232 right 0.62 95.410138 1.021363 0.812453
6_2 6 13232 13355 right 1.23 94.060430 1.219165 0.958232
6_3 6 13295 13420 left 1.25 90.620860 1.097766 0.831089
6_4 6 13355 13492 right 1.37 85.576517 0.970061 0.694266
6_5 6 13420 13602 left 1.82 NaN 0.851080 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 5 0.017686 9.15 19.672 0.48378 92.917277 1.132127 0.086623 0.088637 2 0.683967 0.891545 2 0.730898 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 979 1835 12 max_break MaxBreakCriteria(consider_end_as_break=True, m... 8.56 1.259167 92.857232 0.923175 0.745904
1 5230 5982 8 max_break MaxBreakCriteria(consider_end_as_break=True, m... 7.52 1.175000 87.808553 0.914782 0.650693
2 9715 10630 12 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.15 0.985000 100.656484 0.676807 0.570474
3 12994 14690 27 max_break MaxBreakCriteria(consider_end_as_break=True, m... 16.96 1.106667 100.847040 0.879673 0.742630
4 20287 22435 25 max_break MaxBreakCriteria(consider_end_as_break=True, m... 21.48 1.134800 82.417073 0.903417 0.625303


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 979 1062 left 0.83 105.263158 1.160621 1.018089
0_1 0 1062 1172 left 1.10 106.852358 1.177377 1.048420
0_2 0 1117 1227 right 1.10 107.564058 1.143444 1.024778
0_3 0 1172 1282 left 1.10 107.944130 1.100256 0.989706
0_4 0 1227 1339 right 1.12 106.093671 1.079993 0.955065
... ... ... ... ... ... ... ... ... ...
4 4_22 4 21943 21985 right 0.42 60.606061 0.910531 0.459864
4_23 4 21985 22090 right 1.05 58.347189 0.971656 0.472396
4_25 4 22090 22130 right 0.40 60.000000 0.910531 0.455266
4_26 4 22130 22227 right 0.97 67.813348 0.859493 0.480974
4_28 4 22353 22435 left 0.82 NaN 0.786764 NaN

84 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:03,  2.01it/s]
 22%|██▏       | 2/9 [00:00<00:03,  2.16it/s]
 33%|███▎      | 3/9 [00:01<00:04,  1.42it/s]
 44%|████▍     | 4/9 [00:02<00:03,  1.64it/s]
 56%|█████▌    | 5/9 [00:02<00:02,  1.83it/s]
 67%|██████▋   | 6/9 [00:03<00:01,  1.51it/s]
 78%|███████▊  | 7/9 [00:04<00:01,  1.66it/s]
 89%|████████▉ | 8/9 [00:04<00:00,  1.83it/s]
100%|██████████| 9/9 [00:05<00:00,  1.56it/s]
100%|██████████| 9/9 [00:05<00:00,  1.65it/s]

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.117766 0.913574
Trial2 0 288 978 10 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.90 1.235000 98.030680 1.135156 0.940431
Test11 Trial1 0 630 1112 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.82 1.012857 102.691989 1.089851 0.935974
1 2832 4138 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 13.06 1.305714 79.290506 0.699701 0.459350
2 4488 5198 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 7.10 1.604286 91.005498 1.073694 0.812935
3 7848 8782 11 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.34 1.253636 85.665068 0.876606 0.631880
4 9530 10168 9 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.38 1.231111 83.159936 0.866376 0.627456
5 11032 11465 5 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.33 1.306000 88.480662 0.814981 0.619937
6 13118 13602 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.84 1.343333 92.247498 1.042166 0.833501
002 TimeMeasure1 Test5 Trial1 0 280 738 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.58 1.241667 91.804548 1.336648 1.086528
Trial2 0 115 592 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.77 1.203333 89.651780 1.525990 1.140575
Test11 Trial1 0 480 1138 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.58 1.501429 79.867370 0.876770 0.606076
1 2458 3992 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 15.34 1.120714 79.699313 0.780370 0.531763
2 5828 7165 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 13.37 1.531429 79.649525 0.907134 0.606389
3 7422 7892 5 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.70 1.224000 68.876437 1.017318 0.574567
4 15088 15520 4 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.32 1.212500 81.999762 0.605622 0.418481
MS 001 TimeMeasure1 Test5 Trial1 0 673 1185 8 max_break MaxBreakCriteria(consider_end_as_break=True, m... 5.12 1.127500 106.918436 1.125898 1.016039
Trial2 0 415 920 8 max_break MaxBreakCriteria(consider_end_as_break=True, m... 5.05 1.043750 107.443125 1.069114 0.995062
Test11 Trial1 0 979 1835 12 max_break MaxBreakCriteria(consider_end_as_break=True, m... 8.56 1.259167 92.857232 0.923175 0.745904
1 5230 5982 8 max_break MaxBreakCriteria(consider_end_as_break=True, m... 7.52 1.175000 87.808553 0.914782 0.650693
2 9715 10630 12 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.15 0.985000 100.656484 0.676807 0.570474
3 12994 14690 27 max_break MaxBreakCriteria(consider_end_as_break=True, m... 16.96 1.106667 100.847040 0.879673 0.742630
4 20287 22435 25 max_break MaxBreakCriteria(consider_end_as_break=True, m... 21.48 1.134800 82.417073 0.903417 0.625303


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.089851 0.935974
1 2832 4138 14 max_break MaxBreakCriteria(consider_end_as_break=True, m... 13.06 1.305714 79.290506 0.699701 0.459350
2 4488 5198 7 max_break MaxBreakCriteria(consider_end_as_break=True, m... 7.10 1.604286 91.005498 1.073694 0.812935
3 7848 8782 11 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.34 1.253636 85.665068 0.876606 0.631880
4 9530 10168 9 max_break MaxBreakCriteria(consider_end_as_break=True, m... 6.38 1.231111 83.159936 0.866376 0.627456
5 11032 11465 5 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.33 1.306000 88.480662 0.814981 0.619937
6 13118 13602 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.84 1.343333 92.247498 1.042166 0.833501


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=1.4709975, 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.773952 1.057163 2 0.790726 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.056063 0.890358
1 3853 5300 18 max_break MaxBreakCriteria(consider_end_as_break=True, m... 14.47 1.355000 86.077669 1.055774 0.752985
2 7740 8677 10 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.37 1.033000 91.138330 0.957432 0.720453
3 9532 10005 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.73 1.226667 88.473947 1.041943 0.770051
4 11142 11464 4 max_break MaxBreakCriteria(consider_end_as_break=True, m... 3.22 0.970000 98.290233 0.833365 0.663786
5 11982 13602 15 max_break MaxBreakCriteria(consider_end_as_break=True, m... 16.20 1.302667 87.979239 1.058551 0.794920


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=1.4709975, 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.773952 1.057163 2 0.790726 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.056063 0.890358
1 3853 5300 18 max_break MaxBreakCriteria(consider_end_as_break=True, m... 14.47 1.355000 86.077669 1.055774 0.752985
2 7740 8677 10 max_break MaxBreakCriteria(consider_end_as_break=True, m... 9.37 1.033000 91.138330 0.957432 0.720453
3 9532 10005 6 max_break MaxBreakCriteria(consider_end_as_break=True, m... 4.73 1.226667 88.473947 1.041943 0.770051
4 11142 11464 4 max_break MaxBreakCriteria(consider_end_as_break=True, m... 3.22 0.970000 98.290233 0.833365 0.663786
5 11982 13602 15 max_break MaxBreakCriteria(consider_end_as_break=True, m... 16.20 1.302667 87.979239 1.058551 0.794920


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.45935 0.699701 1 0.45935 0 NaN NaN NaN NaN NaN NaN NaN NaN 0


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

Estimated memory usage: 16 MB

Gallery generated by Sphinx-Gallery