[英]use dplyr mutate to create new columns based on a vector of column names
[英]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
我想生成一个新列,该列从v1
或v2
中获取值,具体取决于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
做到这一点的一种方法:
pivot_longer
带入长格式filter
bind_cols()
v1
和v2
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.