Home > Net >  Mutate with function over multiple columns
Mutate with function over multiple columns

Time:11-10

I have questionnaire (EHP30) answers from a list of participants, where they are rating something between 0 and 4, or -9 for not relevant. The overall score is the sum of the scores scaled to 100. If there are any not relevant answers they are ignored (unless they are all not relevant, in which case the output is missing). Any missing items sets the whole output to missing.

I have written a function that calculates the score from an input vector:

ehp30_sexual <- function(scores = c(0, 0, 0, 0, 0)){
  if(anyNA(scores)){
    return(NA)
  } else if(!all(scores %in% c(-9, 0, 1, 2, 3, 4))){
    stop("Values not in correct range (-9, 0, 1, 2, 3, 4)")
  } else if(length(scores) != 5){
    stop("Must be vector length of 5")
  } else if(all(scores == -9)){
    return(NA)
  } else if(any(scores == -9)){
    newscores <- scores[which(scores != -9)]
    sum(newscores) * 100 / (4 * length(newscores))
  } else {
    sum(scores) * 100 / (4 * length(scores))
  }
}

I wish to apply this function to each row of a dataframe using mutate if possible (or apply if not):

ans <- c(NA, -9, 0, 1, 2, 3, 4)
set.seed(1)
data <- data.frame(id = 1:10,
                   ePainAfterSex = sample(ans, 10, TRUE),
                   eWorriedSex = sample(ans, 10, TRUE),
                   eAvoidSex = sample(ans, 10, TRUE),
                   eGuiltyNoSex = sample(ans, 10, TRUE),
                   eFrustratedNoSex = sample(ans, 10, TRUE))

Any ideas? I'm happy to rewrite the function or use a case_when solution if it is any simpler.

CodePudding user response:

Using dplyr::rowwise() and c_across() (inspired by @edvinsyk’s answer):

set.seed(1)
library(dplyr)

data %>%
  rowwise() %>%
  mutate(score = ehp30_sexual(
    c_across(ePainAfterSex:eFrustratedNoSex)
  )) %>%
  ungroup()
# A tibble: 10 × 7
      id ePainAfterSex eWorriedSex eAvoidSex eGuiltyNoSex eFrustratedNoSex score
   <int>         <dbl>       <dbl>     <dbl>        <dbl>            <dbl> <dbl>
 1     1            NA           0        NA           -9               -9  NA  
 2     2             1           0         4            3                3  55  
 3     3             4          NA         2           NA                4  NA  
 4     4            NA           2         2            1                1  NA  
 5     5            -9           2        NA            4                1  NA  
 6     6             2          -9        NA           NA                1  NA  
 7     7             4           3         3            1               -9  68.8
 8     8             0           3         2            0                1  30  
 9     9             3          -9         2            3               NA  NA  
10    10            -9           4        -9           -9                4 100 

CodePudding user response:

Is something like this what you're after? Seems easier than the function you supplied.

data = tibble(data)

data |> 
    mutate(across(where(is.numeric), ~ ifelse(.x == -9, NA, .x))) |> 
    rowwise() |> 
    mutate(index = sum(c_across(2:6), na.rm = TRUE)) |> 
    ungroup() |> 
    mutate(score = round(scales::rescale(index, to = c(0, 100))))

      id ePainAfterSex eWorriedSex eAvoidSex eGuiltyNoSex eFrustratedNoSex index score
   <int>         <dbl>       <dbl>     <dbl>        <dbl>            <dbl> <dbl> <dbl>
 1     1            NA           0        NA           NA               NA     0     0
 2     2             1           0         4            3                3    11   100
 3     3             4          NA         2           NA                4    10    91
 4     4            NA           2         2            1                1     6    55
 5     5            NA           2        NA            4                1     7    64
 6     6             2          NA        NA           NA                1     3    27
 7     7             4           3         3            1               NA    11   100
 8     8             0           3         2            0                1     6    55
 9     9             3          NA         2            3               NA     8    73
10    10            NA           4        NA           NA                4     8    73

  •  Tags:  
  • r
  • Related