We can use mutate
with across
from dplyr
for multiple columns
library(dplyr) # 1.0.0
df %>%
group_by(A) %>%
mutate(across(everything(), list(mean = ~ mean(.))))
If it is to replace original column with mean
df %>%
group_by(A) %>%
mutate(across(everything(), mean, na.rm = TRUE))
NOTE: na.rm = TRUE
is added in case there are any NA values as by default it is na.rm = FALSE
Or to have fine control over the column names
df1 <- df %>%
group_by(A) %>%
mutate(across(everything(), list(mean = ~ mean(.)), .names = "{col}mean"))
df1
# A tibble: 6 x 5
# Groups: A [3]
# D A B Dmean Bmean
# <dbl> <dbl> <dbl> <dbl> <dbl>
#1 -76 83 -0.613 -75 -0.506
#2 -74 83 -0.4 -75 -0.506
#3 -72 82 -0.5 -71 -0.59
#4 -70 82 -0.68 -71 -0.59
#5 -44 81 -0.13 -43 -0.195
#6 -42 81 -0.26 -43 -0.195
Or using ave
for multiple columns, get the vector of column names that are not the grouping ("A" with setdiff
('nm1'), Loop over the vector, subset the dataset column, use that in ave
and assign it back to the dataset as new columns with paste
nm1 <- setdiff(names(df), "A")
df[paste0(nm1, "mean")] <- lapply(nm1, function(nm) ave(df[[nm]], df$A))