Skip to content
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

Implementing rolling median function for metrics.py #38

Merged
merged 10 commits into from
May 21, 2024

Conversation

frey-perez
Copy link
Collaborator

This function implements the rolling median function, a function meant to pre-process acceleration data before determining angle_relative_to_horizontal values. All relevant unit tests are included.

Copy link

codecov bot commented May 15, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (fd1a714) to head (9d91309).

Current head 9d91309 differs from pull request most recent head ae24b23

Please upload reports for the commit ae24b23 to get more accurate results.

Additional details and impacted files
@@              Coverage Diff              @@
##           development       #38   +/-   ##
=============================================
  Coverage       100.00%   100.00%           
=============================================
  Files                4         4           
  Lines              113       120    +7     
=============================================
+ Hits               113       120    +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.



def rolling_median(
acceleration: models.Measurement, window_size: int = 51
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this in measurement units, whereas rolling_median and rolling_std are in seconds?

@@ -53,3 +56,59 @@ def angle_relative_to_horizontal(
angle_degrees = np.degrees(angle_radians)

return models.Measurement(measurements=angle_degrees, time=acceleration.time)


def rolling_median(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be in core/computations.py see rolling_std()

src/wristpy/processing/metrics.py Outdated Show resolved Hide resolved
src/wristpy/processing/metrics.py Outdated Show resolved Hide resolved
src/wristpy/processing/metrics.py Outdated Show resolved Hide resolved
if window_size <= 1:
raise ValueError("window size must be greater than 1.")

if window_size % 2 == 0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two options:

  1. Raise a ValueError.
  2. Don't do this; even numbers are fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If 1 add test, if 2 is covered by regular tests.

)

radius = window_size // 2
raw_data = acceleration.measurements
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't alias it.

@@ -79,3 +79,57 @@ def test_angle_relative_to_horizontal(
assert angle_z_results.measurements.shape == (1,), (
f"Expected anglez shape: {(1,)}," f"got({angle_z_results.measurements.shape})"
)


def test_rolling_median_wrong_ndims() -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above; this should work.

metrics.rolling_median(test_measurement)


def test_rolling_median_window_size() -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let numpy handle this; we dont need to handle it.

@@ -53,3 +56,59 @@ def angle_relative_to_horizontal(
angle_degrees = np.degrees(angle_radians)

return models.Measurement(measurements=angle_degrees, time=acceleration.time)


def rolling_median(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to moving for consistency with moving_mean and moving_std

@ReinderVosDeWael
Copy link
Contributor

Why not use https://docs.pola.rs/py-polars/html/reference/expressions/api/polars.Expr.rolling_median.html and other polars.rolling_* methods instead of implementing all of these?

Fair point - for now, as there's some design questions to be answered regarding handling of even window size and unit of window size, lets leave this for now. I'll make an issue out of it though so we can reassess this when those issues are resolved.

-Renamed rollingmedian to moving Median
-Moved moving median function into computations
-Moved unit tests for moving_median to test_computations.py
-changed moving median to Polars implementation.
-window size is based on time, matching the other moving functions
-
Copy link
Contributor

@ReinderVosDeWael ReinderVosDeWael left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two relatively small comments, but see if you can make sure the moving_median matches the input implementation of moving_mean so we can use them interchangeably.

accelerometer data in an np.array and 2) time, a pl.Series containing
datetime.datetime objects.

window_size: The size of the overlapping window within which the median will be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overlapping with what? Isn't it just the size of the window?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By overlapping i just mean the windows will overlap in terms of which samples make up the window, as the window is sliding down one sample at a time. Should I edit it, or just remove it if that's implicitly understood?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, how about

"""Applies moving median to acceleration data.

Step size for the window is hard-coded to 1 sample. 

    Args:

...
"""

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes exactly, I'll make that edit.

measurements_polars_df = measurements_polars_df.set_sorted("time")
offset = -((window_size // 2) + 1)
offset_str = str(offset) + "s"
moving_median_df = measurements_polars_df.select(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function will not be able to take the moving median of anything but acceleration as it will fail on data that isn't N-by-3. Are we sure that we never need this for any other measurement? If no, can we just copy the implementation of moving_mean as I believe this one is valid for any N-by-M array.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true I can edit this to cover any amount of cols like so:

moving_median_df = measurements_polars_df.select(
       [
           pl.median("*").rolling(
               index_column="time", period=f"{window_size}s", offset=offset_str
           )
       ]
   )

   return models.Measurement(
       measurements=moving_median_df.drop("time").to_numpy(),
       time=measurements_polars_df["time"],
   )
   
   

@frey-perez frey-perez merged commit d91eace into development May 21, 2024
6 checks passed
@frey-perez frey-perez deleted the freymon_dev_rolling_median branch May 21, 2024 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants