Search code examples
rsignals

Filtfilt on specific rows (data blocks) of data frame


I have a data frame with a trial column, an index column and a time series (Fy) data column. I would like to use filtfilt() on each trial independently, and the result will be the original data frame with the time series data column filtered.

Example dataset (df):

Trial Index Fy
1 1 1.3
1 2 1.4
1 3 1.5
1 4 1.6
2 5 2.4
2 6 2.5
2 7 2.6
2 8 2.7

My filter (from the signal package):

bf <- butter(4, 30/(1000/2), type="low") 

I can use filtfilt() on a full column like:

df$Fy <- filtfilt(bf, df$Fy)

However, this doesn't allow the filter to recognize that their are different trials in the column, and each trial needs to be filtered seperately.

I have tried:

df %>%
group_by(Trial) %>%
filtfilt(bf, df$Fy) #filters specific data column

And then I tried creating a list of indices by trial:

index <- df %>%
  group_by(Trial) %>%
  summarise(Indices = paste(sort(unique(Index)), collapse = " "))

And tried lapply for the specific column I'm trying to filter:

df$Fy <- lapply(index, function(x) filtfilt(bf, x))

Solution

  • Here is 1 approach.

    1. Break the dataframe into a list of dataframes by group using group_split.
    2. Map each dataframe using map from the purrr package.
    3. Bind the rows back into a normal dataframe.
    library(dplyr)
    library(signal)
    library(purrr)
    
    df<-tibble::tribble(
          ~Trial, ~Index, ~Fy,
              1L,     1L, 1.3,
              1L,     2L, 1.4,
              1L,     3L, 1.5,
              1L,     4L, 1.6,
              2L,     5L, 2.4,
              2L,     6L, 2.5,
              2L,     7L, 2.6,
              2L,     8L, 2.7
          )
    
    bf <- butter(4, 30/(1000/2), type="low") 
    
    apply_my_filter<-function(df){
     df$Fy <- filtfilt(bf, df$Fy)
     return(df)
    }
    
    df_filtered<-df %>%
      group_split(Trial) %>%
      map(apply_my_filter) %>%
      bind_rows()
    
    df_filtered
    #> # A tibble: 8 × 3
    #>   Trial Index     Fy
    #>   <int> <int>  <dbl>
    #> 1     1     1 0.0884
    #> 2     1     2 0.0777
    #> 3     1     3 0.0662
    #> 4     1     4 0.0544
    #> 5     2     5 0.156 
    #> 6     2     6 0.137 
    #> 7     2     7 0.117 
    #> 8     2     8 0.0962
    

    Created on 2022-01-09 by the reprex package (v2.0.1)