Okay, took me a little bit to figure out what you want, but here is a solution:
cols.to.sub <- paste0("mm", 1:3)
df1 <- ddply(
df, .(ID, variable),
function(x) {
x[cols.to.sub] <- t(t(as.matrix(x[cols.to.sub])) - unlist(x[x$phase == 3, cols.to.sub]))
x
} )
This produces (first 6 rows):
ID phase variable mm1 mm2 mm3
1 101 1 A -2 -2 -2
2 101 2 A -1 -1 -1
3 101 3 A 0 0 0
4 101 1 B -2 -2 -2
5 101 2 B -1 -1 -1
6 101 3 B 0 0 0
Generally speaking the best way to debug this type of issue is to put a browser()
statement inside the function you are passing to ddply
, so you can examine the objects at your leisure. Doing so would have revealed that:
- The data frame passed to your function includes the ID columns, as well as the phase columns, so your
mm
columns are not the first three (hence the need to definecols.to.sub
) - Even if you address that, you can't operate on data frames that have unequal dimensions, so what I do here is convert to matrix, and then take advantage of vector recycling to subtract the one row from the rest of the matrix. I need to
t
(transpose) because vector recycling is column-wise.