使用管道运算符使用同一行中另一列的变量值寻址一列

Address a column with the variable value of another column in the same row using the pipe operator

一个例子data.frame:

library(tidyverse)
example <- data.frame(matrix(sample.int(15),5,3),
                      sample(c("A","B","C"),5,replace=TRUE) ) %>%
                      `colnames<-`( c("A","B","C","choose") ) %>% print()

输出:

   A  B  C choose
1  9 12  4      A
2  7  8 13      C
3  5  1  2      A
4 15  3 11      C
5 14  6 10      B

“选择”列表示应从 A、B、C 列中选择哪个值

我对“结果”栏的拙劣解决方案:

cols <- c(A=1,B=2,C=3)
col_index <- cols[example$choose]
xy <- cbind(1:nrow(example),col_index)
example %>% mutate(result = example[xy])

输出:

   A  B  C choose result
1  9 12  4      A      9
2  7  8 13      C     13
3  5  1  2      A      5
4 15  3 11      C     11
5 14  6 10      B      6

我相信 dplyr 有一个更优雅的解决方案, 但是我尝试使用“rowwise”或“accross”失败了。

这里有可能得到一个单行解决方案吗?

有效的选择是利用 row/column 索引

example$result <- example[1:3][cbind(seq_len(nrow(example)), 
          match(example$choose, names(example)))]

dplyr,我们可以用getrowwise

library(dplyr)
example %>%
    rowwise %>%
    mutate(result = get(choose)) %>%
    ungroup

或者使用 cur_data()

而不是 get
example %>% 
   rowwise %>%
   mutate(result = cur_data()[[choose]]) %>%
   ungroup

或带有 row/column 索引的向量化选项

example %>% 
   mutate(result = select(., where(is.numeric))[cbind(row_number(), 
       match(choose, names(example)))])

这是另一种方法:

library(dplyr)
library(tidyr)

example %>% 
  pivot_longer(
    -choose,
  ) %>% 
  filter(choose == name) %>% 
  select(result=value) %>% 
  bind_cols(example) 
  
  result     A     B     C choose
   <int> <int> <int> <int> <chr> 
1      9     6     9     1 B     
2     14     5     2    14 C     
3      7     8     7     3 B     
4     15    15     4    12 A     
5     11    13    10    11 C