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))