You could use the same merge and aggregate in a little more readable way. Merging the actual df with result of aggregate on left outer join all.x = TRUE
will do the job. I hope this is better to understand.
df <- data.frame(id=c(01,02,03,04),category=c("AB","BC","AB","CD"),
quantity=c(235,987,366,287))
df <- merge(df,aggregate(quantity ~ category, data=df, sum),"category",all.x = TRUE)
names(df)[4] <- "sum.category"
df
# category id quantity.x sum.category
# AB 1 235 601
# AB 3 366 601
# BC 2 987 987
# CD 4 287 287
If you still want a more easy-to-understand way, then sql is the best option. For this you might need sqldf
library. We are doing the same aggregate and merge back to the actual df in an sql way. Its more like a self-join thing. And the sql codes are quite easier to understand
library (sqldf)
dfnew<-sqldf("select a.*,b.sum_quantity
from df a left join
(select category, sum(quantity) sum_category
from df group by 1) b
on a.category=b.category")
dfnew
# category id quantity sum_category
# AB 1 235 601
# BC 2 987 987
# AB 3 366 601
# CD 4 287 287