我想在pmax / pmin中使用一定范围的列,而不是键入所有列的名称。
#sample data
foo <- data.frame(sapply(letters, function(x) x = sample(1:10,5)))
#this works
bar <- foo %>%
mutate(maxcol = pmax(a,b,c))
# this does not work
bar <- foo %>%
mutate(maxcol = pmax(a:z))
最终我也想要这样的东西
bar <- foo %>%
mutate_at(a:z = pmax(a:z))
这是一个选项,可一次对所有行,所有列执行一个函数调用。
foo %>%
mutate(maxcol = do.call(pmax, subset(., select = a:e)))
# a b c d e f g h i j k l m n o p q r s t u v w x y z maxcol
# 1 1 4 9 2 4 4 1 10 2 3 10 4 7 1 10 9 8 2 8 9 5 1 9 1 10 9 9
# 2 5 2 5 3 5 2 8 8 5 8 2 3 6 10 9 3 5 8 7 4 6 9 8 5 8 3 5
# 3 10 9 6 1 7 10 6 4 4 7 6 6 2 7 5 5 4 1 10 7 3 10 5 10 1 7 10
# 4 8 1 4 8 9 3 3 9 10 1 8 5 8 4 4 8 6 10 5 2 9 5 7 7 3 1 9
# 5 2 10 2 9 8 9 9 6 7 5 9 2 5 5 7 4 2 5 4 8 4 6 6 2 9 6 10
您可以使用冒号来选择部分或全部列,甚至可以选择任意列:
foo %>%
mutate(maxcol = do.call(pmax, subset(., select = c(a:e,g))))
# a b c d e f g h i j k l m n o p q r s t u v w x y z maxcol
# 1 1 4 9 2 4 4 1 10 2 3 10 4 7 1 10 9 8 2 8 9 5 1 9 1 10 9 9
# 2 5 2 5 3 5 2 8 8 5 8 2 3 6 10 9 3 5 8 7 4 6 9 8 5 8 3 8
# 3 10 9 6 1 7 10 6 4 4 7 6 6 2 7 5 5 4 1 10 7 3 10 5 10 1 7 10
# 4 8 1 4 8 9 3 3 9 10 1 8 5 8 4 4 8 6 10 5 2 9 5 7 7 3 1 9
# 5 2 10 2 9 8 9 9 6 7 5 9 2 5 5 7 4 2 5 4 8 4 6 6 2 9 6 10
与其他答案(通常使用所谓的惯用方法)相比,应首选此原因,原因是:
max
函数对于框架的每一行都调用一次;没有使用R的向量化ops,效率低下,应尽可能避免;pmax
是,该帧的每一列都被调用一次,在这种情况下,这听起来可能更糟,但实际上更接近于最佳状态。我的答案最接近akrun,因为我们正在内select
读取数据mutate
。如果您想使用dplyr::select
over base::subset
,则需要将其分解为
foo %>%
mutate(maxcol = select(., a:e, g) %>% do.call(pmax, .))
我认为基准测试可以更好地证明这一点。使用提供的5x26框架,我们可以看到明显的改进:
set.seed(42)
foo <- data.frame(sapply(letters, function(x) x = sample(1:10,5)))
microbenchmark::microbenchmark(
Dom = {
foo %>%
rowwise() %>%
summarise(max= max(c_across(a:z)))
},
akr = {
foo %>%
mutate(maxcol = reduce(select(., a:z), pmax))
},
r2 = {
foo %>%
mutate(maxcol = do.call(pmax, subset(., select = a:z)))
}
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# Dom 6.6561 7.15260 7.61574 7.38345 7.90375 11.0387 100
# akr 4.2849 4.69920 4.96278 4.86110 5.18130 7.0908 100
# r2 2.3290 2.49285 2.68671 2.59180 2.78960 4.7086 100
让我们尝试使用稍大的5000x26:
set.seed(42)
foo <- data.frame(sapply(letters, function(x) x = sample(1:10,5000,replace=TRUE)))
microbenchmark::microbenchmark(
Dom = {
foo %>%
rowwise() %>%
summarise(max= max(c_across(a:z)))
},
akr = {
foo %>%
mutate(maxcol = reduce(select(., a:z), pmax))
},
r2 = {
foo %>%
mutate(maxcol = do.call(pmax, subset(., select = a:z)))
}
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# Dom 515.6437 563.6060 763.97348 811.45815 883.00115 1775.2366 100
# akr 4.6660 5.1619 11.92847 5.74050 6.50625 293.7444 100
# r2 2.9253 3.4371 4.24548 3.71845 4.27380 14.0958 100
最后一个无疑显示了使用的后果rowwise
。akrun的答案与该答案之间的相对性能几乎等于5行,从而强化了这样的前提,即列方式要比行方式好(并且一次要快于两者)。
(也可以使用purrr::invoke
,如果确实需要,尽管它不能加快速度:
library(purrr)
foo %>%
mutate(maxcol = invoke(pmax, subset(., select = a:z)))
### microbenchmark(...)
# Unit: milliseconds
# expr min lq mean median uq max neval
# Dom 7.8292 8.40275 9.02813 8.97345 9.38500 12.4368 100
# akr 4.9622 5.28855 8.78909 5.60090 6.11790 309.2607 100
# r2base 2.5521 2.74635 3.01949 2.90415 3.21060 4.6512 100
# r2purrr 2.5063 2.77510 3.11206 2.93415 3.33015 5.2403 100
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句