Создайте новый столбец в data.frame, используя условия каждой строки - PullRequest
0 голосов
/ 23 августа 2010

У меня есть фрейм данных R:

> tab1
  pat  t conc
1  P1  0  788
2  P1  5  720
3  P1 10  655
4  P2  0  644
5  P2  5  589
6  P2 10  544

Я пытаюсь создать новый столбец для conc в процентах от conc при t = 0 для каждого пациента. Как и многие другие, я попробовал:

tab1$conct0 <- tab1$conc / tab1$conc[tab1$t == 0  & tab1$pat == tab1$pat]

Но мне явно не хватает правильного кода, который означает "conc WHERE t == 0 AND pat == pat для этой конкретной строки"

Я уверен, что мог бы использовать цикл for или что-то еще, но надеялся, что было что-то проще?

Спасибо

Ответы [ 5 ]

2 голосов
/ 25 августа 2010

с плиром:

library(plyr)
ddply(tab1, "pat", transform, conct0 = conc / conc[t == 0])
1 голос
/ 31 августа 2010

Я бы использовал 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
1 голос
/ 23 августа 2010

Немного временный способ сделать это, но работает в этом случае:

xt <- xtabs(conc~t+pat,tab1)
tab1$conct0 <- as.numeric(t(t(xt)/xt[1,])) # need to use transpose because of the way matrix vector indexing works

xt[1,] представляет строку для t=0; Вы также можете использовать xt["0",].

1009 ** * Редактировать 1010 ** * 1011

Более надежный способ:

tabt <- subset(tab1,t==0)
names(tabt)[3] <- "conct0"
tab1 <- merge(tab1,tabt[,c(1,3)])
tab1$conct0 <- tab1$conc/tab1$conct0
1 голос
/ 23 августа 2010

Я бы нашел начальную концентрацию для каждого пациента с:

startConc <- tab1[tab1$t == 0,]

, который дает (из данных вашего примера)

  pat t conc
1  P1 0  788
4  P2 0  644

После этого вы можете использовать apply

newconc <- apply(tab1, 1, function(x){as.numeric(x[3])/startConc[startConc$pat==x[1],3]})

что дает вам

[1] 1.0000000 0.9137056 0.8312183 1.0000000 0.9145963 0.8447205
0 голосов
/ 23 августа 2010

Если вы можете с уверенностью предположить, что ваша концентрация не возрастает со временем, то самый короткий и быстрый расчетный ответ на этот вопрос будет ...

tab1$concp <- ave(tab1$conc, tab1$pat, FUN = function(x) x/max(x))
...