我需要执行一个基本group_by
/mutate
利用辅助分组变量操作。例如:
df <- data.frame(
u = c(0, 0, 1, 0, 1),
v = c(8, 4, 2, 3, 5)
)
df %>%
group_by(tmp = cumsum(u)) %>%
mutate(w = cumprod(v)) %>%
ungroup %>%
select(-tmp)
我的问题是,如果df
碰巧已经包含一个名为tmp
I的列,它将丢失它。
当然,我可以选择一个非常奇特的名称,而不是tmp
降低碰撞的可能性(或者甚至可以选择strrep("z", max(nchar(names(df))) + 1)
确定的名称),但是我更喜欢一个更干净的解决方案。
换句话说,我正在寻找dplyr
与此data.table
行等效的内容:
setDT(df)[, w := cumprod(v), by = cumsum(u)]
我们可以创建一个函数来解决这个问题。假设要创建的临时分组变量为'tmp',则通过与数据集的列名称连接并调用make.unique
,如果数据集中已经存在'tmp'列,则重复的列将被重命名为'tmp.1 '。使用!!
,将列命名为'tmp.1'(来自nm1
)不会影响数据集中已经存在的'tmp'。如果没有“ tmp”列,则分组列将被命名为“ tmp”,随后使用select
f1 <- function(dat, grpCol, Col) {
grpCol <- enquo(grpCol)
Col <- enquo(Col)
changeCol <- "tmp"
nm1 <- tail(make.unique(c(names(dat), changeCol)), 1)
dat %>%
group_by(!! (nm1) := cumsum(!! grpCol)) %>%
mutate(w = cumprod(!!Col)) %>%
ungroup %>%
select(-one_of(nm1))
}
-运行功能
f1(df, u, v)
# A tibble: 5 x 3
# u v w
# <dbl> <dbl> <dbl>
#1 0 8.00 8.00
#2 0 4.00 32.0
#3 1.00 2.00 2.00
#4 0 3.00 6.00
#5 1.00 5.00 5.00
f1(df %>% mutate(tmp = 1), u, v) #create a 'tmp' column in dataset
# A tibble: 5 x 4
# u v tmp w
# <dbl> <dbl> <dbl> <dbl>
#1 0 8.00 1.00 8.00
#2 0 4.00 1.00 32.0
#3 1.00 2.00 1.00 2.00
#4 0 3.00 1.00 6.00
#5 1.00 5.00 1.00 5.00
作为后续(有关@Frank的评论),关于传递表达式
expr <- quos(tmp = cumsum(u), w = cumprod(v))
#additional checks outside the function
names(expr)[1] <- if(names(expr)[1] %in% names(df))
strrep(names(expr)[1], 2) else names(expr)[1]
f2 <- function(dat, exprs ){
dat %>%
group_by(!!! exprs[1]) %>%
mutate(!!! exprs[2])
}
f2(df, expr)
# A tibble: 5 x 4
# Groups: tmp [3]
# u v tmp w
# <dbl> <dbl> <dbl> <dbl>
#1 0 8.00 0 8.00
#2 0 4.00 0 32.0
#3 1.00 2.00 1.00 2.00
#4 0 3.00 1.00 6.00
#5 1.00 5.00 2.00 5.00
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句