doctorate
doctorate

Reputation: 1413

How to do rowwise computations to dynamically create columns using tidyverse?

imagine I have the following tibble as my data. As you can see there are columns with names like name1.x, and name2.x, but actually there are tens of them sitting in my real data set.

MWE

test <- tibble(subject = c(1,1,1, 2, 2, 2, 2, 3, 3), 
               name1.x = c(2, 4, 5, 2, 3, 6, 8, 1.2, 10), 
               name2.x = c(1, 6, 8, 1.2, 9, 6, 66, 1.2, 20), 
               visit = factor(c("base", "v1", "v2", "base", "v1", "v2", "v3", "base", "v1")))

  subject name1.x name2.x visit
    <dbl>   <dbl>   <dbl> <fct>
1       1     2       1   base 
2       1     4       6   v1   
3       1     5       8   v2   
4       2     2       1.2 base 
5       2     3       9   v1   
6       2     6       6   v2   
7       2     8      66   v3   
8       3     1.2     1.2 base 
9       3    10      20   v1   

What do I want?

to do re-scaling to the values in my target columns based on their base visit and of course creating new columns based on their names. All v values corresponding to a subject shall be re-scaled to their corresponding base values. So for subject 1, name1.x first value is 2 and it happens to be a base value so it must give us 2/2=1, second value is 4 must give us 4/2=2, and so on... Those new values must be created in a new column with a name corresponding to its cognate column, name1.x shall be given name1.y and name2.x -> name2.y. How to achieve this using the tidyverse?

Upvotes: 0

Views: 103

Answers (1)

jazzurro
jazzurro

Reputation: 23574

If I am correctly reading your question, I think the following is one way to solve your question. First, I defined groups using subject. For each subject, I handled division as you described. Basically, I handled the division for each column that contains name in column names. When I did that, I used the value which has base in the same row as denominator. Finally, I modified column names so that I could have the desired column names. I hope this will help you.

library(dplyr)

group_by(test, subject) %>% 
  mutate_at(vars(contains("name")),
            .funs = list(y = ~./.[visit == "base"])) %>% 
  rename_at(vars(contains("_")),
            .funs = list(~sub(x = ., pattern = "(?<=.)._", replacement = "", perl = TRUE)))

#  subject name1.x name2.x visit name1.y name2.y
#    <dbl>   <dbl>   <dbl> <fct>   <dbl>   <dbl>
#1       1     2       1   base     1        1  
#2       1     4       6   v1       2        6  
#3       1     5       8   v2       2.5      8  
#4       2     2       1.2 base     1        1  
#5       2     3       9   v1       1.5      7.5
#6       2     6       6   v2       3        5  
#7       2     8      66   v3       4       55  
#8       3     1.2     1.2 base     1        1  
#9       3    10      20   v1       8.33    16.7

Upvotes: 3

Related Questions