Search code examples
rfor-loopsubset

How to subtract control group values from multiple treatmeant groups' values in R data frame?


I have a following data frame in R:

Group Value
Control 2
Control 3
Treament1 7
Treament1 4
Treament2 5
Treament2 6

How do I get:

Group Value
Treament1 - Control 5
Treament1 - Control 1
Treament2 - Control 3
Treament2 - Control 0

I was thinking of looping and using the subset function:

controldf <- subset(df, Group == "Control")
newdf <- subset(df, Group != "Control")
newvalue <- c()
for(group in unique(df$group)) {
    if(group != "Control") {
        newvalue <- c(newvalue, subset(df, Group == group)$value - controldf$value)
    }
}
newdf$value <- newvalue

...but this looks bad (and is very slow with larger data frames). :(

Is there a better way to do this?


Solution

  • Solution 1 uses dplyr and tidyr libraries. An id column is added to the data.frame assuming that subjects are ordered within group.

    library(dplyr)
    library(tidyr)
    df |>
        group_by(Group) |>
        mutate(id = row_number()) |>
        pivot_wider(names_from = Group, values_from = Value) |>
        mutate(across(starts_with("Treament"), ~.x - Control))  |>
        select(starts_with("Treament")) |>
        rename_with(~sprintf("%s - Control", .x)) |>
        pivot_longer(everything(), names_to = "Group", values_to = "Value") |>
        arrange(Group)
    ##>  # A tibble: 4 × 2
    ##>   Group               Value
    ##>   <chr>               <int>
    ##> 1 Treament1 - Control     5
    ##> 2 Treament1 - Control     1
    ##> 3 Treament2 - Control     3
    ##> 4 Treament2 - Control     3
    
    

    Solution 2 uses the purrr library:

    library(purrr)
    
    spl <- with(df, split(Value, Group))
    
    imap_dfr(spl[startsWith(names(spl), "Treament")], ~{
        data.frame(Group= sprintf("%s - Control", .y),
                   Value = .x - spl$Control)
        })
    
    ##>                 Group Value
    ##> 1 Treament1 - Control     5
    ##> 2 Treament1 - Control     1
    ##> 3 Treament2 - Control     3
    ##> 4 Treament2 - Control     3