Home > Mobile >  Take the first value of group of columns in R
Take the first value of group of columns in R

Time:10-21

I have some data:

data

structure(list(WBC_BASELINE = c(2.9, NA, NA, 6.9, NA, NA, NA, 
NA, NA, NA, 7.4, 12.8, NA, NA, NA, NA, NA, 4.2, NA, NA), WBC_FIRST = c(2.4, 
14.8, 11, 7.3, 4.5, NA, NA, 6.1, 7.7, 16.2, 5.3, 10.3, 14.5, 
NA, NA, 12.8, 3.7, 4.7, 16.6, 9.3), neuts_BASELINE = c(2, NA, 
NA, 5.4, NA, NA, NA, NA, NA, NA, 4.96, 8.9, NA, NA, NA, NA, NA, 
NA, NA, NA), neuts_FIRST = c(1.5, 13, 5.8, 4.5, 1.6, NA, NA, 
1.7, 4.3, 9.3, 3.4, 5.8, 10.1, NA, NA, 9.7, 2.3, 3.5, 5, 8.2)), row.names = c(NA, 
20L), class = "data.frame")

In the dataset I have some blood test results (in this case WBC and neuts taken at 2 time points - baseline, and first). I want to select the baseline value if it exists, else take the first value.

I can do this separately for WBC and neuts, but I want to do it for 20 different blood tests without hard coding it each time...

Hard coding way:

data %>% mutate(WBC_first_value=ifelse(!is.na(WBC_BASELINE), WBC_BASELINE, WBC_FIRST)) %>% 
mutate(neuts_first_value=ifelse(!is.na(neuts_BASELINE), neuts_BASELINE, neuts_FIRST)) 

Please note that each blood test is always followed by _BASELINE and _FIRST

I'd be grateful for any help please!

CodePudding user response:

We could automate this process with some data wrangling using pivot_longer and pivot_wider in combination:

library(dplyr)
library(tidyr)
  data %>% 
    mutate(rn = row_number()) %>%
    pivot_longer(cols = -rn, names_to = c('grp', '.value'),
                 names_sep = "_") %>% 
    group_by(grp) %>%
    transmute(rn, new = coalesce(BASELINE, FIRST)) %>% 
    pivot_wider(names_from = grp, values_from = new) %>%
    select(-rn) %>%
    bind_cols(data, .)

output:

   WBC_BASELINE WBC_FIRST neuts_BASELINE neuts_FIRST  WBC neuts
1           2.9       2.4           2.00         1.5  2.9  2.00
2            NA      14.8             NA        13.0 14.8 13.00
3            NA      11.0             NA         5.8 11.0  5.80
4           6.9       7.3           5.40         4.5  6.9  5.40
5            NA       4.5             NA         1.6  4.5  1.60
6            NA        NA             NA          NA   NA    NA
7            NA        NA             NA          NA   NA    NA
8            NA       6.1             NA         1.7  6.1  1.70
9            NA       7.7             NA         4.3  7.7  4.30
10           NA      16.2             NA         9.3 16.2  9.30
11          7.4       5.3           4.96         3.4  7.4  4.96
12         12.8      10.3           8.90         5.8 12.8  8.90
13           NA      14.5             NA        10.1 14.5 10.10
14           NA        NA             NA          NA   NA    NA
15           NA        NA             NA          NA   NA    NA
16           NA      12.8             NA         9.7 12.8  9.70
17           NA       3.7             NA         2.3  3.7  2.30
18          4.2       4.7             NA         3.5  4.2  3.50
19           NA      16.6             NA         5.0 16.6  5.00
20           NA       9.3             NA         8.2  9.3  8.20

CodePudding user response:

You could do this with a loop!

vars <- c("WBC", "neuts")
for(v in vars){
  df[,paste0(v, "_new")] <- ifelse(!is.na(df[,paste0(v, "_BASELINE")]), df[,paste0(v, "_BASELINE")], df[,paste0(v, "_FIRST")])
}

Or with sapply:

sapply(vars, function(v) ifelse(!is.na(df[,paste0(v, "_BASELINE")]),df[,paste0(v, "_BASELINE")], df[,paste0(v, "_FIRST")]))

Also could define vars programmatically:

vars <- unique(gsub(pattern = "^([A-Za-z] )_[A-Za-z] ", "\\1", names(df)))
  • Related