Try
left_join(dt1,
dt1 %>%
filter(x2==1) %>%
group_by(x) %>%
summarise(a=mean(y)), by='x') %>%
mutate(z=y/a)%>%
head()
# x x2 y a z
#1 1 1 1.41 1.4 1.0071429
#2 1 1 1.39 1.4 0.9928571
#3 1 2 1.90 1.4 1.3571429
#4 1 2 2.10 1.4 1.5000000
#5 1 2 0.90 1.4 0.6428571
#6 1 2 1.10 1.4 0.7857143
Or using data.table
library(data.table)
dt2 <- dt1[x2==1,list(a=mean(y)) , by=x]
setkey(dt1, x)
res <- dt1[dt2][,z:=y/a]
head(res)
# x x2 y a z
#1: 1 1 1.41 1.4 1.0071429
#2: 1 1 1.39 1.4 0.9928571
#3: 1 2 1.90 1.4 1.3571429
#4: 1 2 2.10 1.4 1.5000000
#5: 1 2 0.90 1.4 0.6428571
#6: 1 2 1.10 1.4 0.7857143
Update
A more compact option for dplyr
as suggested by @aosmith is
dt1 %>%
group_by(x) %>%
mutate(a=mean(y[x2==1]), z=y/a)