简体   繁体   中英

Rolling mean function that treats data as cyclical

I have EMG data that represents a single complete cycle of activity and would like to use a rolling/moving mean function to rectify the data on a moving window. Is there any r library with function/option combination that will treat the data as cyclic and use the last N samples to window the beginning of the cycle and the first N samples to window the end of the cycle? Currently using zoo::rollmean() but need to trim some part of the mean values depending on the align option chosen. I've also looked at data.table::frollmean(), RcppRoll::roll_mean(), and forecast::ma(). They all seem to work the same without and possibility of wrapping the data. I know there are many more functions from other libraries so my hope is that someone knows of one to do this automatic wrapping/padding.

Here is an example, I have padded one array by borrowing from either side of the original data so that the rolling mean gives values over the entire array (grey line compared to unpadded red line).

# Rolling mean with cyclical data
library(zoo)
t <- seq(0,4*pi,,100)                    #Time array
y <- 5*sin(t) + 2*rnorm(100)             #Noisy sine wave
s1 <- rollmean(y, 10, na.pad = TRUE)     #Pad with NA to maintain array size
ypad = c(y[96:100], y, y[1:4])           #Pad y with ends of array 
s2 <- rollmean(ypad, 10, na.pad = FALSE) #No need to pad
df <- tibble(t,y,s1,s2)                  #Make data frame for plotting
ggplot(df, aes(x=t)) +
  geom_line(aes(y=s2), col = 'grey', size=2, alpha=0.5) +
  geom_line(aes(y=y), col = 'blue') +
  geom_line(aes(y=s1), col = 'red', size=1)

Use filter (part of base R) with circular=TRUE. Be sure that dplyr is not loaded as it clobbers filter.

In general, if at each point the number of points over which we are averaging is n then at each point we average the n points ending at the point floor(n/2) positions ahead of the current position so that for n=10 we average the 10 points at offsets -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 from the current point where for circular averaging we interpret the offsets circularly. We can arrange for that with rollmean by appending the first 5 points onto the end of the series and prefixing the last 4 points onto the beginning. (This is different than what was assumed in the question where appending 4 and prefixing 5 was assumed.)

library(zoo)

set.seed(123)  # to make example reproducible

t <- seq(0,4*pi,,100)
y <- 5*sin(t)+2*rnorm(100) 

yy <- c(y[97:100], y, y[1:5])
res1 <- rollmean(yy, 10)

res2 <- c(filter(y, rep(1/10, 10), circular = TRUE))

all.equal(res1, res2)
## [1] TRUE

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM