根据名称存储在另一列中的现有列创建新列 (dplyr)

con*_*der 9 r dplyr

考虑以下数据集:

\n
df <- tibble(v1 = 1:5, v2= 101:105, v3 = c("v1", "v2", "v1", "v2", "v1"))\n\n# A tibble: 5 \xc3\x97 3\n     v1    v2 v3   \n  <int> <int> <chr>\n1     1   101 v1   \n2     2   102 v2   \n3     3   103 v1   \n4     4   104 v2   \n5     5   105 v1  \n
Run Code Online (Sandbox Code Playgroud)\n

我想生成一个新列,该列从 或 中获取值v1v2具体取决于中列出的列v3

\n
    # A tibble: 5 \xc3\x97 4\n     v1    v2 v3       v4\n  <int> <int> <chr> <dbl>\n1     1   101 v1        1\n2     2   102 v2      102\n3     3   103 v1        3\n4     4   104 v2      104\n5     5   105 v1        5\n
Run Code Online (Sandbox Code Playgroud)\n

通常,我会使用if_else,或者如果我有更多情况,则使用case_when。但是,我有很多列,所以我不想有case_when很多行长的语句。有没有办法让 R 将值解释为v3列名?我尝试过拥抱这个表达并{{ }}使用.data[[ ]]表达式,但我似乎无法找出正确的语法。

\n

akr*_*run 8

一个tidyverse选择是rowwise使用提取cur_data()

\n
library(dplyr)\ndf %>% \n  rowwise %>%\n  mutate(v4 = cur_data()[[v3]]) %>% \n  ungroup\n# A tibble: 5 \xc3\x97 4\n     v1    v2 v3       v4\n  <int> <int> <chr> <int>\n1     1   101 v1        1\n2     2   102 v2      102\n3     3   103 v1        3\n4     4   104 v2      104\n5     5   105 v1        5\n
Run Code Online (Sandbox Code Playgroud)\n
\n

或者一个紧凑的方法是get或者在之后rowwise

\n
df %>%\n  rowwise %>%\n  mutate(v4 = get(v3)) %>%\n  ungroup\n
Run Code Online (Sandbox Code Playgroud)\n
\n

或者在base R,使用行/列索引来加快执行速度

\n
df$v4 <- as.data.frame(df[1:2])[cbind(seq_len(nrow(df)), \n      match(df$v3, names(df)))]\ndf$v4\n[1]   1 102   3 104   5\n
Run Code Online (Sandbox Code Playgroud)\n


r2e*_*ans 8

这是一种矢量化方法,不需要逐行或map逐一进行。

df %>%
  mutate(v4 = cbind(v1,v2)[ cbind(row_number(), match(v3, c("v1", "v2"))) ])
# # A tibble: 5 x 4
#      v1    v2 v3       v4
#   <int> <int> <chr> <int>
# 1     1   101 v1        1
# 2     2   102 v2      102
# 3     3   103 v1        3
# 4     4   104 v2      104
# 5     5   105 v1        5
Run Code Online (Sandbox Code Playgroud)


Tar*_*Jae 6

这是我们可以使用的一种方法pivot_longer

  1. 变成长格式pivot_longer
  2. filter
  3. bind_cols() v1v2
library(tidyr)
library(dplyr)
df %>% 
  pivot_longer(
    -v3,
    names_to = "name",
    values_to = "v4"
  ) %>% 
  filter(v3 == name) %>% 
  bind_cols(v1 = df$v1, v2=df$v2) %>% 
  select(v1, v2, v3, v4)
Run Code Online (Sandbox Code Playgroud)
  v1    v2 v3       v4
  <int> <int> <chr> <int>
1     1   101 v1        1
2     2   102 v2      102
3     3   103 v1        3
4     4   104 v2      104
5     5   105 v1        5
Run Code Online (Sandbox Code Playgroud)


Tho*_*ing 5

diag您可以使用+ as.matrix(或t)尝试以下基本 R 代码

transform(
  df,
  v4 = diag(as.matrix(df[v3]))
)
Run Code Online (Sandbox Code Playgroud)

或者

transform(
  df,
  v4 = diag(t(df[v3]))
)
Run Code Online (Sandbox Code Playgroud)

这使

  v1  v2 v3  v4
1  1 101 v1   1
2  2 102 v2 102
3  3 103 v1   3
4  4 104 v2 104
5  5 105 v1   5
Run Code Online (Sandbox Code Playgroud)