按行平均超过增加号。在 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 列的范围并获得列的平均值 selected。然后,我们可以更改新列的名称并将输出绑定回原始数据框。在这里,我使用 names(a)[-1]
以便代码更灵活并且适用于任何其他数据帧。
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, .)
输出
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
我想执行这样的操作。
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 列的范围并获得列的平均值 selected。然后,我们可以更改新列的名称并将输出绑定回原始数据框。在这里,我使用 names(a)[-1]
以便代码更灵活并且适用于任何其他数据帧。
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, .)
输出
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