odar
odar

Reputation: 431

How to use gather() with more than one x-variable?

I am relatively new to R and I am struggling with the following problem: I have a data frame that consists of two sets of x and y variables i.e. x1, y1 and x2, y2. I would like to use gather or any other function that could help to create a new data frame with merged x1 and x2 variables into a single x variable. I have tried to use gather but can see only examples applied to data frames with a single x variable. Bellow is my reprex with the desired output as well.

Your help is really appreciated. Thank you!

library(tidyr)

(df <- data.frame(x1=c(1,2,3),y1=c(10,14,12), x2=c(2,3,4),y2=c(12,13,11)))
#>   x1 y1 x2 y2
#> 1  1 10  2 12
#> 2  2 14  3 13
#> 3  3 12  4 11

(df_tall <- gather(df,"z", "y", y1:y2))
#>   x1  z  y
#> 1  1 y1 10
#> 2  2 y1 14
#> 3  3 y1 12
#> 4  1 x2  2
#> 5  2 x2  3
#> 6  3 x2  4
#> 7  1 y2 12
#> 8  2 y2 13
#> 9  3 y2 11

# desired output
print('Desired output')
#> [1] "Desired output"
(df_mod <- data.frame(x=c(1,2,2,3,3,4),y=c(10,14,12,12,13,11), z=c("y1", "y1", "y2", "y1", "y2", "y2")))
#>   x  y  z
#> 1 1 10 y1
#> 2 2 14 y1
#> 3 2 12 y2
#> 4 3 12 y1
#> 5 3 13 y2
#> 6 4 11 y2

Created on 2020-04-03 by the reprex package (v0.2.1)

Upvotes: 4

Views: 237

Answers (3)

akrun
akrun

Reputation: 887981

We can use data.table methods

library(data.table)
melt(setDT(df), measure = patterns('^x', '^y'),
        variable.name = 'z', value.name = c('x', 'y'))
#   z x  y
#1: 1 1 10
#2: 1 2 14
#3: 1 3 12
#4: 2 2 12
#5: 2 3 13
#6: 2 4 11

Upvotes: 1

Ronak Shah
Ronak Shah

Reputation: 389335

gather has been replaced with pivot_longer in tidyr which allows this.

tidyr::pivot_longer(df, cols = everything(), 
                        names_to = c('.value', 'z'),
                        names_pattern = '(.)(.)')

#   z       x     y
#  <chr> <dbl> <dbl>
#1 1         1    10
#2 2         2    12
#3 1         2    14
#4 2         3    13
#5 1         3    12
#6 2         4    11

.value is used when we want part of column name as a data in separate column. In names_pattern we use regex to specify groups in which columns are divided. In this case, we use each character as separate group, hence the pattern. ((.)(.)).

Upvotes: 3

Edward
Edward

Reputation: 19541

Can use reshape here:

reshape(df, direction="long", varying=1:4, sep="", timevar="z")
    z x  y id
1.1 1 1 10  1
2.1 1 2 14  2
3.1 1 3 12  3
1.2 2 2 12  1
2.2 2 3 13  2
3.2 2 4 11  3

Upvotes: 2

Related Questions