Home > Software engineering >  Dynamic selection by a vector in Tidyverse
Dynamic selection by a vector in Tidyverse

Time:10-25

I have a tibble A such:

X1 X2 X3
x1_1 x2_1 x3_1
x1_2 x2_2 x3_2
x1_3 x2_3 x3_3
x1_4 x2_4 x3_4

And a Vector Y: (X2,X1,X3,X1...)

I want to select into a single vector B: (x2_1,x1_2,x3_3,x1_4...) only the values in the table A, such the B[n] element it is selected within the column Y[n].

I'd like to do this within a tidyverse pipeline, I want to avoid any for or apply.

I tried, after conversions of Y into integers referring to the position of the columns of A:

A %>% add_column(Y = Y) %>%
  mutate(B = .[,Y])

but it does not vectorize properly.

CodePudding user response:

We may use rowwise

library(dplyr)
A %>% 
   add_column(Y = Y) %>%
   rowwise %>%
   mutate(B = cur_data()[[Y]]) %>%
   ungroup

-output

# A tibble: 4 × 5
  X1    X2    X3    Y     B    
  <chr> <chr> <chr> <chr> <chr>
1 x1_1  x2_1  x3_1  X2    x2_1 
2 x1_2  x2_2  x3_2  X1    x1_2 
3 x1_3  x2_3  x3_3  X3    x3_3 
4 x1_4  x2_4  x3_4  X1    x1_4 

Or with get

A %>%
     mutate(Y = Y)  %>% 
     rowwise %>%
     mutate(B = get(Y)) %>% 
     ungroup

Or using a vectorized solution

A %>%
   mutate(B = .[cbind(row_number(), match(Y, names(.)))])
    X1   X2   X3    B
1 x1_1 x2_1 x3_1 x2_1
2 x1_2 x2_2 x3_2 x1_2
3 x1_3 x2_3 x3_3 x3_3
4 x1_4 x2_4 x3_4 x1_4

Or use a vectorized row/column indexing in base R

A$B <- A[cbind(seq_len(nrow(A)), match(Y, names(A)))]

data

A <- structure(list(X1 = c("x1_1", "x1_2", "x1_3", "x1_4"), X2 = c("x2_1", 
"x2_2", "x2_3", "x2_4"), X3 = c("x3_1", "x3_2", "x3_3", "x3_4"
)), class = "data.frame", row.names = c(NA, -4L))

Y <- c("X2", "X1", "X3", "X1")

CodePudding user response:

This works too:

A %>% add_column(Y = Y) %>%
  mutate(B = map2(Y, 1:n(), function(x, y){.[[x]][y]}))
  • Related