You can use the to_long
function from the sjmisc-package for this purpose. This function is a convenient for-loop, which calls multiple gather()
calls.
# create sample
mydat <- data.frame(age = c(20, 30, 40),
sex = c("Female", "Male", "Male"),
score_t1 = c(30, 35, 32),
score_t2 = c(33, 34, 37),
score_t3 = c(36, 35, 38),
speed_t1 = c(2, 3, 1),
speed_t2 = c(3, 4, 5),
speed_t3 = c(1, 8, 6))
# check tidyr. score is gathered, however, speed is not
tidyr::gather(mydat, "time", "score", score_t1, score_t2, score_t3)
> age sex speed_t1 speed_t2 speed_t3 time score
> 1 20 Female 2 3 1 score_t1 30
> 2 30 Male 3 4 8 score_t1 35
> 3 40 Male 1 5 6 score_t1 32
> 4 20 Female 2 3 1 score_t2 33
> 5 30 Male 3 4 8 score_t2 34
> 6 40 Male 1 5 6 score_t2 37
> 7 20 Female 2 3 1 score_t3 36
> 8 30 Male 3 4 8 score_t3 35
> 9 40 Male 1 5 6 score_t3 38
# gather multiple columns. both time and speed are gathered.
to_long(mydat, "time", c("score", "speed"),
c("score_t1", "score_t2", "score_t3"),
c("speed_t1", "speed_t2", "speed_t3"))
> age sex time score speed
> (dbl) (fctr) (chr) (dbl) (dbl)
> 1 20 Female score_t1 30 2
> 2 30 Male score_t1 35 3
> 3 40 Male score_t1 32 1
> 4 20 Female score_t2 33 3
> 5 30 Male score_t2 34 4
> 6 40 Male score_t2 37 5
> 7 20 Female score_t3 36 1
> 8 30 Male score_t3 35 8
> 9 40 Male score_t3 38 6
In this case, the time
vector (indicating the gathered groups) just takes one of the multiple gathered column name. If this is too confusing, you can also just number the ID variable:
to_long(mydat, "time", c("score", "speed"),
c("score_t1", "score_t2", "score_t3"),
c("speed_t1", "speed_t2", "speed_t3"),
recode.key = TRUE)
> age sex time score speed
> (dbl) (fctr) (dbl) (dbl) (dbl)
> 1 20 Female 1 30 2
> 2 30 Male 1 35 3
> 3 40 Male 1 32 1
> 4 20 Female 2 33 3
> 5 30 Male 2 34 4
> 6 40 Male 2 37 5
> 7 20 Female 3 36 1
> 8 30 Male 3 35 8
> 9 40 Male 3 38 6
See ?to_long
for more examples.
I'm not sure, but I think I read something on GitHub that "multiple column gathering" is also planned for tidyr somewhen...