-
Notifications
You must be signed in to change notification settings - Fork 5
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
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
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. |
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? |
src/wristpy/processing/metrics.py
Outdated
|
||
|
||
def rolling_median( | ||
acceleration: models.Measurement, window_size: int = 51 |
There was a problem hiding this comment.
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?
src/wristpy/processing/metrics.py
Outdated
@@ -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( |
There was a problem hiding this comment.
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
if window_size <= 1: | ||
raise ValueError("window size must be greater than 1.") | ||
|
||
if window_size % 2 == 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two options:
- Raise a ValueError.
- Don't do this; even numbers are fine.
There was a problem hiding this comment.
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.
src/wristpy/processing/metrics.py
Outdated
) | ||
|
||
radius = window_size // 2 | ||
raw_data = acceleration.measurements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't alias it.
tests/unit/test_metrics.py
Outdated
@@ -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: |
There was a problem hiding this comment.
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.
tests/unit/test_metrics.py
Outdated
metrics.rolling_median(test_measurement) | ||
|
||
|
||
def test_rolling_median_window_size() -> None: |
There was a problem hiding this comment.
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.
src/wristpy/processing/metrics.py
Outdated
@@ -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( |
There was a problem hiding this comment.
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
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 -
There was a problem hiding this 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.
src/wristpy/core/computations.py
Outdated
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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:
...
"""
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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"],
)
-changed the wording of doc string for clarity.
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.