Я бы использовал tapply
. Учитывая ваши данные:
tab1 <- data.frame(
pat = c(rep("P1", 3), rep("P2", 3)),
t = c(0, 5, 10, 0, 5, 10),
conc = c(788, 720, 655, 644, 589, 544))
этот однострочник сделает это для вас так, как вы намекаете в своем посте:
> tab1$conc / tab1$conc[tab1$t == 0][tapply(tab1$pat, tab1$pat)]
[1] 1.0000000 0.9137056 0.8312183 1.0000000 0.9145963 0.8447205
tapply
без какой-либо функции создает индекс строки, соответствующий идентификатору пациента (номеру) для каждой строки. Я считаю этот метод довольно быстрым и полезным. Но это предполагает, что идентификаторы вашего пациента заказаны. Если это проблема, мы можем убедиться, что они соответствуют порядку идентификатора пациента:
> tab1$conc / tab1$conc[tab1$t == 0][order(unique(tab1$pat))][tapply(tab1$pat, tab1$pat)]
[1] 1.0000000 0.9137056 0.8312183 1.0000000 0.9145963 0.8447205
Если вы используете это часто, я бы написал для него функцию, например, такую:
myFract <- function(obj, x = "conc", id = "pat", time = "t", start = NULL) {
if (is.null(start)) start <- min(obj[, time])
ii <- which(obj[, time] == start)
ii <- ii[order(unique(obj[, id]))][tapply(obj[, id], obj[, id])]
obj[, x] / obj[ii, x]
}
такой, что:
> myFract(tab1)
[1] 1.0000000 0.9137056 0.8312183 1.0000000 0.9145963 0.8447205