-
Notifications
You must be signed in to change notification settings - Fork 7
127 implement mims #193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
127 implement mims #193
Changes from 28 commits
e45a2d3
a41a24d
3def235
f86e31a
140ddc8
eeff57c
46531f4
c3ca41e
4257962
c8eba12
3fbf9af
14a335a
122f597
4fb8aec
a65f83f
b95ce39
3cdc786
cf98353
24a91f9
63a76dd
68c8aa1
7e33a83
0a8fc3a
b9b293c
a58181e
94950db
c08fc68
b78e02e
d9b66dc
7bee464
023ec70
b178ed3
4f1374b
4f04c46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,7 +29,7 @@ | |
| Literal["ggir", "gradient"], | ||
| ] = "gradient", | ||
| epoch_length: float = 5, | ||
| activity_metric: Literal["enmo", "mad", "ag_count"] = "enmo", | ||
| activity_metric: Literal["enmo", "mad", "ag_count", "mims"] = "enmo", | ||
| nonwear_algorithm: Sequence[Literal["ggir", "cta", "detach"]] = ["ggir"], | ||
| verbosity: int = logging.WARNING, | ||
| output_filetype: Optional[Literal[".csv", ".parquet"]] = None, | ||
|
|
@@ -51,7 +51,7 @@ | |
| path should end in the save file name in either .csv or .parquet formats. | ||
| thresholds: The cut points for the light, moderate, and vigorous thresholds, | ||
| given in that order. Values must be asscending, unique, and greater than 0. | ||
| Default values are optimized for subjects ages 7-11 [1]. | ||
| Default values are optimized for subjects ages 7-11 [1][3]. | ||
| calibrator: The calibrator to be used on the input data. | ||
| epoch_length: The temporal resolution in seconds, the data will be down sampled | ||
| to. It must be > 0.0. | ||
|
|
@@ -79,6 +79,10 @@ | |
| Going S, Norman JE, Pate R. Defining accelerometer thresholds for activity | ||
| intensities in adolescent girls. Med Sci Sports Exerc. 2004 Jul;36(7):1259-66. | ||
| PMID: 15235335; PMCID: PMC2423321. | ||
| [3] Karas M, Muschelli J, Leroux A, Urbanek J, Wanigatunga A, Bai J, | ||
| Crainiceanu C, Schrack J Comparison of Accelerometry-Based Measures of Physical | ||
| Activity: Retrospective Observational Data Analysis Study JMIR Mhealth Uhealth | ||
| 2022;10(7):e38077 URL: https://mhealth.jmir.org/2022/7/e38077 DOI: 10.2196/38077 | ||
| """ | ||
| logger.setLevel(verbosity) | ||
|
|
||
|
|
@@ -91,8 +95,10 @@ | |
| thresholds = thresholds or (0.029, 0.338, 0.604) | ||
| elif activity_metric == "ag_count": | ||
| thresholds = thresholds or (100, 3000, 5200) | ||
| elif activity_metric == "mims": | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can probably add a test for mims in test_orchestrator? To make sure it handles the dynamic range/thresholds properly? |
||
| thresholds = thresholds or (10.558, 15.047, 19.614) | ||
|
|
||
| if not (0 <= thresholds[0] < thresholds[1] < thresholds[2]): | ||
| if not (0 <= thresholds[0] < thresholds[1] < thresholds[2]): # type: ignore | ||
| message = "Threshold values must be >=0, unique, and in ascending order." | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
@@ -122,6 +128,7 @@ | |
| thresholds=thresholds, | ||
| calibrator=calibrator, | ||
| epoch_length=epoch_length, | ||
| activity_metric=activity_metric, | ||
| verbosity=verbosity, | ||
| output_filetype=output_filetype, | ||
| nonwear_algorithm=nonwear_algorithm, | ||
|
|
@@ -140,6 +147,7 @@ | |
| nonwear_algorithm: Sequence[Literal["ggir", "cta", "detach"]] = ["ggir"], | ||
| verbosity: int = logging.WARNING, | ||
| output_filetype: Optional[Literal[".csv", ".parquet"]] = None, | ||
| activity_metric: Literal["enmo", "mad", "ag_count", "mims"] = "enmo", | ||
| ) -> Dict[str, models.OrchestratorResults]: | ||
| """Runs main processing steps for wristpy on directories. | ||
|
|
||
|
|
@@ -155,13 +163,14 @@ | |
| output: Path to directory data will be saved to. | ||
| thresholds: The cut points for the light, moderate, and vigorous thresholds, | ||
| given in that order. Values must be asscending, unique, and greater than 0. | ||
| Default values are optimized for subjects ages 7-11 [1]. | ||
| Default values are optimized for subjects ages 7-11 [1][2]. | ||
| calibrator: The calibrator to be used on the input data. | ||
| epoch_length: The temporal resolution in seconds, the data will be down sampled | ||
| to. It must be > 0.0. | ||
| nonwear_algorithm: The algorithm to be used for nonwear detection. | ||
| verbosity: The logging level for the logger. | ||
| output_filetype: Specifies the data format for the save files. | ||
| activity_metric: The metric to be used for physical activity categorization. | ||
|
|
||
| Returns: | ||
| All calculated data in a save ready format as a dictionary of | ||
|
|
@@ -177,6 +186,10 @@ | |
| [1] Hildebrand, M., et al. (2014). Age group comparability of raw accelerometer | ||
| output from wrist- and hip-worn monitors. Medicine and Science in Sports and | ||
| Exercise, 46(9), 1816-1824. | ||
| [2] Karas M, Muschelli J, Leroux A, Urbanek J, Wanigatunga A, Bai J, | ||
| Crainiceanu C, Schrack J Comparison of Accelerometry-Based Measures of Physical | ||
| Activity: Retrospective Observational Data Analysis Study JMIR Mhealth Uhealth | ||
| 2022;10(7):e38077 URL: https://mhealth.jmir.org/2022/7/e38077 DOI: 10.2196/38077 | ||
| """ | ||
| if output is None and output_filetype is not None: | ||
| raise ValueError("If no output is given, output_filetype must be None.") | ||
|
|
@@ -219,6 +232,7 @@ | |
| epoch_length=epoch_length, | ||
| verbosity=verbosity, | ||
| nonwear_algorithm=nonwear_algorithm, | ||
| activity_metric=activity_metric, | ||
| ) | ||
| except Exception as e: | ||
| logger.error("Did not run file: %s, Error: %s", file, e) | ||
|
|
@@ -235,7 +249,7 @@ | |
| Literal["ggir", "gradient"], | ||
| ] = "gradient", | ||
| epoch_length: float = 5.0, | ||
| activity_metric: Literal["enmo", "mad", "ag_count"] = "enmo", | ||
| activity_metric: Literal["enmo", "mad", "ag_count", "mims"] = "enmo", | ||
| nonwear_algorithm: Sequence[Literal["ggir", "cta", "detach"]] = ["ggir"], | ||
| verbosity: int = logging.WARNING, | ||
| ) -> models.OrchestratorResults: | ||
|
|
@@ -254,7 +268,7 @@ | |
| either .csv or .parquet formats. | ||
| thresholds: The cut points for the light, moderate, and vigorous thresholds, | ||
| given in that order. Values must be ascending, unique, and greater than 0. | ||
| Default values are optimized for subjects ages 7-11 [1]. | ||
| Default values are optimized for subjects ages 7-11 [1][3]. | ||
|
frey-perez marked this conversation as resolved.
Outdated
|
||
| calibrator: The calibrator to be used on the input data. | ||
| epoch_length: The temporal resolution in seconds, the data will be down sampled | ||
| to. It must be > 0.0. | ||
|
|
@@ -278,6 +292,10 @@ | |
| calculated from raw acceleration data: a novel method for classifying the | ||
| intensity of adolescents' physical activity irrespective of accelerometer brand. | ||
| BMC Sports Sci Med Rehabil 7, 18 (2015). https://doi.org/10.1186/s13102-015-0010-0. | ||
| [3] Karas M, Muschelli J, Leroux A, Urbanek J, Wanigatunga A, Bai J, | ||
| Crainiceanu C, Schrack J Comparison of Accelerometry-Based Measures of Physical | ||
| Activity: Retrospective Observational Data Analysis Study JMIR Mhealth Uhealth | ||
| 2022;10(7):e38077 URL: https://mhealth.jmir.org/2022/7/e38077 DOI: 10.2196/38077 | ||
| """ | ||
| logger.setLevel(verbosity) | ||
| if output is not None: | ||
|
|
@@ -318,7 +336,10 @@ | |
| calibrated_acceleration, epoch_length=epoch_length | ||
| ) | ||
| activity_measurement = _compute_activity( | ||
| calibrated_acceleration, activity_metric, epoch_length | ||
| calibrated_acceleration, | ||
| activity_metric, | ||
| epoch_length, | ||
| dynamic_range=watch_data.dynamic_range, | ||
| ) | ||
|
|
||
| sleep_detector = analytics.GgirSleepDetection(anglez) | ||
|
|
@@ -329,6 +350,7 @@ | |
| temperature=watch_data.temperature, | ||
| non_wear_algorithms=nonwear_algorithm, | ||
| ) | ||
|
|
||
| nonwear_epoch = nonwear_utils.nonwear_array_cleanup( | ||
| nonwear_array=nonwear_array, | ||
| reference_measurement=activity_measurement, | ||
|
|
@@ -371,8 +393,9 @@ | |
|
|
||
| def _compute_activity( | ||
| acceleration: models.Measurement, | ||
| activity_metric: Literal["ag_count", "mad", "enmo"], | ||
| activity_metric: Literal["ag_count", "mad", "enmo", "mims"], | ||
| epoch_length: float, | ||
| dynamic_range: Optional[tuple[float, float]], | ||
| ) -> models.Measurement: | ||
| """This is a helper function to organize the computation of the activity metric. | ||
|
|
||
|
|
@@ -384,6 +407,10 @@ | |
| activity_metric: The metric to be used for physical activity categorization. | ||
| epoch_length: The temporal resolution in seconds, the data will be down sampled | ||
| to. | ||
| dynamic_range: Tuple of the minimum and maximum accelerometer values. This | ||
| argument is only relevant to the mims metric. Values are taken from watch | ||
| metadata, if no metadata could be extracted, the default | ||
| values of (-8,8) are used. | ||
|
|
||
| Returns: | ||
| A Measurement object with the computed physical activity metric. | ||
|
|
@@ -395,4 +422,14 @@ | |
| ) | ||
| elif activity_metric == "mad": | ||
| return metrics.mean_amplitude_deviation(acceleration, epoch_length=epoch_length) | ||
| elif activity_metric == "mims": | ||
| if dynamic_range is None: | ||
| return metrics.monitor_independent_movement_summary_units( | ||
| acceleration, | ||
| epoch=epoch_length, | ||
| ) | ||
| return metrics.monitor_independent_movement_summary_units( | ||
| acceleration, epoch=epoch_length, dynamic_range=dynamic_range | ||
| ) | ||
|
|
||
| return metrics.euclidean_norm_minus_one(acceleration, epoch_length=epoch_length) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,22 +39,62 @@ | |
| measurements[sensor_name] = models.Measurement( | ||
| measurements=sensor_values, time=time | ||
| ) | ||
|
|
||
| file_type = os.path.splitext(file_name)[1] | ||
|
frey-perez marked this conversation as resolved.
Outdated
|
||
| idle_sleep_mode_flag = False | ||
| if os.path.splitext(file_name)[1] == ".gt3x": | ||
| if file_type == ".gt3x": | ||
| idle_sleep_mode_flag = ( | ||
| data["metadata"]["device_feature_enabled"]["sleep_mode"].lower() == "true" | ||
| ) | ||
|
|
||
| dynamic_range = _extract_dynamic_range( | ||
| metadata=data["metadata"], | ||
| file_type=file_type, # type: ignore | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. make the type ignore specific |
||
| ) | ||
|
|
||
| return models.WatchData( | ||
| acceleration=measurements["acceleration"], | ||
| lux=measurements.get("light"), | ||
| battery=measurements.get("battery_voltage"), | ||
| capsense=measurements.get("capsense"), | ||
| temperature=measurements.get("temperature"), | ||
| idle_sleep_mode_flag=idle_sleep_mode_flag, | ||
| dynamic_range=dynamic_range, | ||
| ) | ||
|
|
||
|
|
||
| def _extract_dynamic_range( | ||
| metadata: dict, file_type: Literal[".gt3x", ".bin"] | ||
| ) -> tuple[float, float]: | ||
| """Extract the dynamic range from metadata. | ||
|
|
||
| Args: | ||
| metadata: Metadata subdictionary where accelerometer range values can be found. | ||
| file_type: Accelerometer data file type. Supports .gt3x and .bin. | ||
|
|
||
| Returns: | ||
| A tuple containing the accelerometer range. | ||
|
|
||
| Raises: | ||
| ValueError: If file type is not supported. | ||
| """ | ||
| if file_type == ".gt3x": | ||
| return ( | ||
| float(metadata.get("info", {}).get("Acceleration Min")), | ||
| float(metadata.get("info", {}).get("Acceleration Max")), | ||
| ) | ||
| elif file_type == ".bin": | ||
| range_str = ( | ||
| metadata.get("Device Capabilities", {}) | ||
| .get("Accelerometer Range") | ||
| .strip() | ||
| .split(" to ") | ||
| ) | ||
| return (float(range_str[0]), float(range_str[1])) | ||
|
|
||
| raise ValueError(f"Unsupported file type given: {file_type}") | ||
|
|
||
|
|
||
| def unix_epoch_time_to_polars_datetime( | ||
| time: np.ndarray, units: Literal["ns", "us", "ms", "s", "d"] = "ns" | ||
| ) -> pl.Series: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.