繁体   English   中英

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

[英]Create new column based on existing columns whose names are stored in another column (dplyr)

考虑以下数据集:

df <- tibble(v1 = 1:5, v2= 101:105, v3 = c("v1", "v2", "v1", "v2", "v1"))

# A tibble: 5 × 3
     v1    v2 v3   
  <int> <int> <chr>
1     1   101 v1   
2     2   102 v2   
3     3   103 v1   
4     4   104 v2   
5     5   105 v1  

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

    # A tibble: 5 × 4
     v1    v2 v3       v4
  <int> <int> <chr> <dbl>
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

通常,我会使用if_else ,或者如果我有更多案例,则使用case_when 但是,我有很多列,所以我宁愿没有一个很长的case_when语句。 有没有办法让 R 将v3中的值解释为列名? 我尝试使用{{ }}来接受表达式并使用.data[[ ]] ,但我似乎无法找出正确的语法。

这是我们如何使用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)
  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

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

transform(
  df,
  v4 = diag(as.matrix(df[v3]))
)

或者

transform(
  df,
  v4 = diag(t(df[v3]))
)

这使

  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

另一种可能的解决方案,使用purrr::pmap_dfr

library(tidyverse)    

df <- tibble(v1 = 1:5, v2= 101:105, v3 = c("v1", "v2", "v1", "v2", "v1"))

df %>% 
  mutate(pmap_dfr(., ~ list(v4 = if_else(..3 == "v1", ..1, ..2))))

#> # A tibble: 5 × 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

这是一种矢量化方法,无需逐行 go 或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

使用cur_data()提取的tidyverse选项将是rowwise

library(dplyr)
df %>% 
  rowwise %>%
  mutate(v4 = cur_data()[[v3]]) %>% 
  ungroup
# A tibble: 5 × 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

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

df$v4 <- as.data.frame(df[1:2])[cbind(seq_len(nrow(df)), 
      match(df$v3, names(df)))]
df$v4
[1]   1 102   3 104   5

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM