Apply dplyr function which contains "group_by" to multiple columns

Viewed 61

Data:

structure(list(Reversal_MSignal = c(0, 0, 0.5, 0, -0.5, 0, 0, 
0, 0, 0), Reversal_MSignal_time = c(1L, 2L, 1L, 2L, 1L, 2L, 3L, 
4L, 5L, 6L)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", 
"data.frame"))

I have a column called Reversal_MSignal and I would like to create a new column called Reversal_MSignal_time which is a number sequence that restarts from 1 when Reversal_MSignal != 0.

The following code creates the wanted column. However, the problem is that I need to create this type of column for a multiple columns

data %>% group_by(gr = cumsum(Reversal_MSignal != 0)) %>% 
  mutate(Reversal_MSignal = row_number()) %>% ungroup() %>% 
  select(-gr)
}

I was thinking about creating a function and then applying it through "apply" or through mutate(across(everything(), Timeframe)).

Timeframe <- function(Column){
group_by(gr = cumsum(Column != 0)) %>% 
  mutate(Column = row_number()) %>% ungroup() %>% 
  select(-gr) %>% 
  rename(Reversal_MSignal_time = Reversal_MSignal)
}

df %>% lapply(., Timeframe)

however, I get this error with lapply and with mutate it doesn't behave as wanted

Error in UseMethod("group_by") : no applicable method for 'group_by' applied to an object of class "c('integer', 'numeric')"

I'm also open to faster solutions however I would prefer those using dplyr package as it is easier for me to understand what is going on

1 Answers

Your main problem was that the group_by inside your function was not being passed the data frame as the first argument. You can try this:

library(tidyverse)

data <- structure(list(Reversal_MSignal = c(0, 0, 0.5, 0, -0.5, 0, 0, 0, 0, 0), 
                       Reversal_MSignal_time = c(1L, 2L, 1L, 2L, 1L, 2L, 3L, 4L, 5L, 6L)), 
                  row.names = c(NA, -10L), 
                  class = c("tbl_df", "tbl", "data.frame"))

Timeframe <- function(data, Column){
    data %>% 
        group_by(gr = cumsum(.data[[Column]] != 0)) %>% 
        mutate("{{Column}}.time" := row_number()) %>% 
        ungroup() %>% 
        select(-gr) %>% 
        rename_with(~str_remove_all(., "\\\""))
}

Timeframe(data, "Reversal_MSignal")
Timeframe(data, "Reversal_MSignal_time")

reduce(names(data), Timeframe, .init = data) 

The reduce statement will loop through all of the columns of data and apply the Timeframe function, and then use the output as the next input.

Related