我有以下代码,我需要从变量中获取列名,然后使用该操作中的指定列有选择地对行执行操作。这是我的简单示例,创建列res
以匹配列targe
t:
library(tidyverse)
tst <- tibble(grp = c("a","a","b","b","c","c"), a = rep(2,6), b = rep(4,6),
c = rep(8,6), target = c(2,2,4,4,8,8), res = rep(0,6))
# create list of columns to iterate over
lst <- unique(tst$grp)
# loop over each column, creating a dummy column with
# the copied value in the matching rows, zeroes elsewhere
for(g in lst) {
tst <- tst %>%
mutate(!!paste("res", g, sep="_") := ifelse(grp == g, !!rlang::sym(g),0)) %>%
select(!!paste("res", g, sep="_")) %>%
cbind(tst)
}
# combine the dummy columns by rowSum
res <- tst %>% select(starts_with("res_")) %>% mutate(res = rowSums(.)) %>%
select(res)
# tidy up the output, result matches the target
tst <- tst %>% select(grp, a, b, c, target) %>% cbind(res)
tst
grp a b c target res
1 a 2 4 8 2 2
2 a 2 4 8 2 2
3 b 2 4 8 4 4
4 b 2 4 8 4 4
5 c 2 4 8 8 8
6 c 2 4 8 8 8
我采用了迭代方法,循环遍历grp
列中的唯一变量,创建临时列,然后rowSum()
来获取最终结果。笨拙,但最终到了那里。
我确信使用map
中的purrr
家庭之一可以采用更优雅的方式。有人可以告诉我如何在没有使用purrr
的循环的情况下执行此操作吗?我真的很难使用这种方法让动态列名工作。提前谢谢。
答案 0 :(得分:1)
不需要你编写循环的东西
library(tidyverse)
tst <- tibble(grp = c("a","a","b","b","c","c"), a = rep(2,6), b = rep(4,6),
c = rep(8,6), target = c(2,2,4,4,8,8), res = rep(0,6))
tst %>%
mutate(res =
case_when(
grp == "a" ~ a,
grp == "b" ~ b,
grp == "c" ~ c
))
# A tibble: 6 x 6
grp a b c target res
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 a 2 4 8 2 2
2 a 2 4 8 2 2
3 b 2 4 8 4 4
4 b 2 4 8 4 4
5 c 2 4 8 8 8
6 c 2 4 8 8 8
注意:如果需要,您可以使用自己的公式代替~ a
如需更多帮助,请参阅?case_when
答案 1 :(得分:0)
也许:
tst %>%
mutate(res = sapply(seq(nrow(tst)), function(x) tst[x,as.character(tst$grp[x])]))
# A tibble: 6 x 6
grp a b c target res
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 a 2 4 8 2 2
2 a 2 4 8 2 2
3 b 2 4 8 4 4
4 b 2 4 8 4 4
5 c 2 4 8 8 8
6 c 2 4 8 8 8
答案 2 :(得分:0)
您可以使用imap
,它会迭代列值及其名称。列值是grp
的值,名称只是序列1,...,6
。
此外,您必须提供数据框本身作为附加参数(df=
到imap
,它转发给它的函数参数。总计:
tst %>%
mutate(res = purrr::imap_dbl(grp, df = .,
.f = function(g, i, df) df[i,g][[1]] # [[1]] turns the result from tibble into a double
))
编辑:我用更大的表格定时此解决方案:
tst <- tst[sample(nrow(tst), 50000, TRUE),]
需要大约50秒。
答案 3 :(得分:0)
这是一个基础R解决方案,也不再是:
# Save all source columns in a matrix. This enables indexing by another matrix
x <- as.matrix(tst[, unique(tst$grp)])
# Matrix of (row, column) pairs to extract from x
i <- cbind(seq_len(nrow(tst)), match(tst$grp, colnames(x)))
tst$res <- x[i]
编辑:更大表的经过时间:
tst <- tst[sample(nrow(tst), 50000, TRUE), ]
0.008s - 0.015s