r - 对列的子集执行 dplyr mutate

标签 r dplyr

我有一个像这样的data.frame(真实的数据集有更多的行和列)

set.seed(15)
dd <- data.frame(id=letters[1:4], matrix(runif(5*4), nrow=4))

#   id        X1        X2        X3        X4        X5
# 1  a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437
# 2  b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670
# 3  c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871
# 4  d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125

我希望能够编写一个 dplyr 语句,在其中我可以选择列的子集并更改它们。 (我正在尝试执行类似于在 data.table 中使用 .SDcols 的操作)。

作为一个简化的示例,我希望能够编写以下函数来添加偶数“X”列的总和和平均值的列,同时保留所有其他列。使用基数 R 的所需输出为

(cols<-paste0("X", c(2,4)))
# [1] "X2" "X4"
cbind(dd,evensum=rowSums(dd[,cols]),evenmean=rowMeans(dd[,cols]))

#   id        X1        X2        X3        X4        X5   evensum  evenmean
# 1  a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.4380811
# 2  b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.8477439
# 3  c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.8387535
# 4  d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.5478768

但我想使用类似 dplyr 的链来做同样的事情。在一般情况下,我希望能够使用 select() 的任何辅助函数,例如 starts_withends_with匹配等以及任何函数。这是我尝试过的

library(dplyr)
partial_mutate1 <- function(x, colspec, ...) {
    select_(x, .dots=list(lazyeval::lazy(colspec))) %>% 
    transmute_(.dots=lazyeval::lazy_dots(...)) %>% 
    cbind(x,.)
}

dd %>% partial_mutate1(num_range("X", c(2,4)), 
    evensum=rowSums(.), evenmean=rowMeans(.))

但是,这会引发一个错误,提示

Error in rowSums(.) : 'x' must be numeric

这似乎是因为 . 似乎指的是整个 date.frame 而不是所选的子集。 (与 rowSums(dd) 相同的错误)。但是,请注意,这会产生所需的输出

partial_mutate2 <- function(x, colspec) {
    select_(x, .dots=list(lazyeval::lazy(colspec))) %>% 
    transmute(evensum=rowSums(.), evenmean=rowMeans(.)) %>% 
    cbind(x,.)
}
dd %>% partial_mutate2(seq(2,ncol(dd),2))

我猜这是某种环境问题?关于如何将参数传递给 partial_mutate1 以便 . 正确地从“select()-ed”数据集中获取值,有什么建议吗?

最佳答案

我是否遗漏了什么或者这是否会按预期工作:

cols <- paste0("X", c(2,4))
dd %>% mutate(evensum = rowSums(.[cols]), evenmean = rowMeans(.[cols]))
#  id        X1        X2        X3        X4        X5   evensum  evenmean
#1  a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.4380811
#2  b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.8477439
#3  c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.8387535
#4  d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.5478768

或者您是否专门寻找自定义函数来执行此操作?

<小时/>

不完全是您正在寻找的内容,但如果您想在管道内执行此操作,您可以在 mutate 内显式使用 select ,如下所示:

dd %>% mutate(xy = select(., num_range("X", c(2,4))) %>% rowSums)
#  id        X1        X2        X3        X4        X5        xy
#1  a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623
#2  b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878
#3  c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071
#4  d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535

但是,如果要应用多个功能,那就有点复杂了。您可以使用辅助函数(..未彻底测试..):

f <- function(x, ...) {
  n <- nrow(x)
  x <- lapply(list(...), function(y) if (length(y) == 1L) rep(y, n) else y)
  matrix(unlist(x), nrow = n, byrow = FALSE)
}

然后像这样应用它:

dd %>% mutate(xy = select(., num_range("X", c(2,4))) %>% f(., rowSums(.), max(.)))
#  id        X1        X2        X3        X4        X5      xy.1      xy.2
#1  a 0.6021140 0.3670719 0.6872308 0.5090904 0.4474437 0.8761623 0.9888592
#2  b 0.1950439 0.9888592 0.8314290 0.7066286 0.9646670 1.6954878 0.9888592
#3  c 0.9664587 0.8151934 0.1046694 0.8623137 0.1411871 1.6775071 0.9888592
#4  d 0.6509055 0.2539684 0.6461509 0.8417851 0.7767125 1.0957535 0.9888592

关于r - 对列的子集执行 dplyr mutate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28751023/

相关文章:

R 绘图轴刻度标签

r - dplyr : Trying to access the elements of a vector stored in a column using an exterior variable as index

R 子集/过滤器不返回任何行

r - 按 R 中的特定条件对列进行排序

r - 如何选择包含某些字符串/字符的特定列?

r - 计算序列长度的包或函数?

r - 带模式的子集

r - 使用 lapply 时出错?

r - 将值分配给特定的data.table列和行

r - summarise_at dplyr 多列