繁体   English   中英

按行平均超过增加号。 在 mutate 中使用 for 循环的列数:dplyr R

[英]Rowwise average over increasing no. of columns using for loop inside mutate : dplyr R

我想做这样的事情。

a <- data.frame(A=c(1,5,9),
                B=c(2,6,10),
                C=c(3,7,11),
                D=c(4,8,12))

a <- a %>% rowwise()
a <- a %>% mutate(mean(c_across(1:2)))
a <- a %>% mutate(mean(c_across(1:3)))
a <- a %>% mutate(mean(c_across(1:4)))

这给出:

A   B   C   D  mean(c_across(1:2)) mean(c_across(1:3)) mean(c_across(1:4))
1   2   3   4                  1.5                   2                 2.5
5   6   7   8                  5.5                   6                 6.5
9   10  11  12                 9.5                  10                10.5

我想使用 for 循环获得相同的结果。 我试过这个:

a <- data.frame(A=c(1,5,9),
                B=c(2,6,10),
                C=c(3,7,11),
                D=c(4,8,12))

a <- a %>% rowwise()
for(i in 2:4){
  a <- a %>% mutate(mean(c_across(1:i)))
}

但它只显示 i=4 的最后一个值的结果

A   B   C   D  mean(c_across(1:i))
1   2   3   4                  2.5
5   6   7   8                  6.5
9   10  11  12                10.5

谁能解释发生了什么? 每当我在使用 dplyr 的时候使用 for 循环,我立刻就觉得我做错了什么。 还有其他更好的方法吗?

您可以使用purrr::reduce (或base::Reduce )进行迭代。

library(tidyverse)

reduce(2:4, ~ mutate(.x, !!paste0("col1to", .y) := mean(c_across(1:.y))), .init = rowwise(a))

# A tibble: 3 x 7
# Rowwise: 
      A     B     C     D col1to2 col1to3 col1to4
  <dbl> <dbl> <dbl> <dbl>   <dbl>   <dbl>   <dbl>
1     1     2     3     4     1.5       2     2.5
2     5     6     7     8     5.5       6     6.5
3     9    10    11    12     9.5      10    10.5
  • base::Reduce版本:
Reduce(\(x, y) mutate(x, !!paste0("col1to", y) := mean(c_across(1:y))), 2:4, init = rowwise(a))

要修复for循环,您需要为每个新列设置不同的列名。 否则,每个新列都将具有相同的名称,即"mean(c_across(1:i))" ,并覆盖前一列。

b <- rowwise(a)
for(i in 2:4) {
  b <- b %>% mutate(!!paste0("col1to", i) := mean(c_across(1:i)))
}

b

使用tidyr::unnest_wider()另一种选择:

a %>%
  rowwise() %>%
  mutate(mean = list(cummean(c_across(1:4))[-1])) %>%
  unnest_wider(mean, names_sep = "_")

使用data.table

setDT(a)[
  , 
  paste0("col", seq_len(ncol(a)-1)) :=  
    transpose(lapply(transpose(.SD), function(x) cummean(x)[-1]))
]

使用 base R 你可以这样做:

cbind(a, t(apply(a, 1, function(x) cummean(x)[-1])))

这是另一个tidyverse选项,它也使用purrr 我们可以使用map遍历列名,以便 select 列的范围并获得所选列的平均值。 然后,我们可以更改新列的名称并将 output 绑定回原始的 dataframe。在这里,我使用names(a)[-1]以便代码更灵活并且适用于任何其他 dataframe。

library(tidyverse)

names(a)[-1] %>% 
  map(~ a %>% 
        select(names(a)[1]:.x) %>% 
        rowMeans(.)) %>%
  set_names(paste0("mean_", names(a)[1], "_", names(a)[-1])) %>%
  bind_cols(a, .)

Output

  A  B  C  D mean_A_B mean_A_C mean_A_D
1 1  2  3  4      1.5        2      2.5
2 5  6  7  8      5.5        6      6.5
3 9 10 11 12      9.5       10     10.5

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM