childmindresearch / wristpy

https://childmindresearch.github.io/wristpy/
GNU Lesser General Public License v2.1
5 stars 5 forks source link

Spike: Classify sleep windows as non-wear or sleep #106

Open Asanto32 opened 1 month ago

Asanto32 commented 1 month ago

Description

Currently, the detection of sleep will also serve as non-wear detection (most non-wear periods will also be detected as sleep, as from an accelerometer point of view they are the same, the inverse is of course-not true, not all sleep periods are detected as non-wear). The current implementation of the Van Hees algorithm for sleep only relies on angle-z (looking the changes in the rolling std of angle-z metric, essentially). As a solution to separate sleep windows from non-wear times, a simple filtering method has been implemented in analytics.remove_nonwear_from_sleep.

However, what if we were to apply some simple classification looking at a few features of both enmo and angle-z during a defined sleep window. Notably:

Some examples highlighting the differences between sleep and non-wear are shown below (blue indicates sleep, red enmo, green anglez, black non-wear)

Screenshot 2024-09-18 at 12 29 35 PM

This is an especially difficult case, non-wear immediately before bed with only a very short window of activity separating the two. Merged into one sleep window (but it has two distinct sleep periods, SIBs) since the activity time is less than the threshold. Screenshot 2024-09-18 at 12 29 04 PM

Screenshot 2024-09-18 at 12 28 48 PM Screenshot 2024-09-18 at 12 28 25 PM

Tasks

Freeform Notes

No response

Asanto32 commented 1 month ago

No rush on this but just some thoughts I had as we go through the Kaggle comp implementation. Since our current sleep detection is actually pretty good, the more time-sensitive, simple question is separating non-wear time from it. @gkiar @vitoetc @frey-perez @ReinderVosDeWael @nx10 @clane9

nx10 commented 1 month ago

If the goal is not to mimick GGIR, I think conceptually non-wear should be regarded as missing data and (if necessary) either imputed or processed by a model that can handle missing data.

Asanto32 commented 1 month ago

I also realize this falls more in the "analysis" branch and not really "wristpy for processing actigraphy data"

Asanto32 commented 1 month ago

If the goal is not to mimick GGIR, I think conceptually non-wear should be regarded as missing data and (if necessary) either imputed or processed by a model that can handle missing data.

I should start looking into using the capsense data and see how we can take advantage of that.

clane9 commented 1 month ago

I agree that the capsense/temperature data would be very useful for distinguishing non-wear from sleep. Otherwise, I agree the two seem hard to distinguish.

I think the ideal approach would be a model/algorithm that takes as input all available raw data, and produces separate predictions for sleep and non-wear. Any pre-processing/feature-engineering/heuristics would be internal to the model. Ofc, it is also fine to have simple heuristics for detecting non-wear/sleep that work fine in most cases. But I would discourage having any of these be upstream of a sleep detection model. Anything you do upstream of the model removes information and limits the model's performance.

In particular, I would discourage trying to detect and code non-wear as missing/NaN before feeding to a sleep detection model. I agree with @nx10 that non-wear is fundamentally missing data. I just think it should be the model's job to detect it.

Asanto32 commented 1 month ago

Just to clarify: non-wear and sleep are currently completely separate algorithms (see detect_non_wear and run_sleep_detection. I just have an additional function that filters out sleep windows (already detected) that have any overlap with detected non-wear periods (basically, I agree that if we detect that the watch isn't being worn, we shouldn't say that someone is sleeping).

Basically the point of my thought process is essentially a second stage that would try to filter out false-positives. But I agree an all-encompassing model would be better. This is almost more of a stop gap idea that I thought is both easier and quicker to implement while we wait for something more robust/nicer.

Does that help clarify a bit? I guess this was better for a meeting and not a forum discussion ha

ReinderVosDeWael commented 1 week ago

Reclassified to spike, time-boxed to 3 days.