2012-11-04 18 views
5

mam ramkę danych z grup 3 i 3 dniach:jak obsługiwać podzbiór ramki danych R w długim formacie?

set.seed(10) 
dat <- data.frame(group=rep(c("g1","g2","g3"),each=3), day=rep(c(0,2,4),3), value=runif(9)) 
# group day value 
# 1 g1 0 0.507478 
# 2 g1 2 0.306769 
# 3 g1 4 0.426908 
# 4 g2 0 0.693102 
# 5 g2 2 0.085136 
# 6 g2 4 0.225437 
# 7 g3 0 0.274531 
# 8 g3 2 0.272305 
# 9 g3 4 0.615829 

że chcą przyjąć log2 i dzielą każdą wartość z wartością w dniu 0 w każdej grupie. Sposób, w jaki to robię teraz jest obliczając każdą grupę dzień w pośrednim kroku:

day_0 <- dat[dat$day==0, "value"] 
day_2 <- dat[dat$day==2, "value"] 
day_4 <- dat[dat$day==4, "value"] 
res <- cbind(0, log2(day_2/day_0), log2(day_4/day_0)) 
rownames(res) <- c("g1","g2","g3") 
colnames(res) <- c("day_0","log_ratio_day_2_day_0","log_ratio_day_4_day_0") 
# day_0 log_ratio_day_2_day_0 log_ratio_day_4_day_0 
# g1  0   -0.7261955    -0.249422 
# g2  0   -3.0252272    -1.620346 
# g3  0   -0.0117427    1.165564 

Jaki jest właściwy sposób obliczania res bez pośredniego etapu?

Odpowiedz

4

Twój przyjaciel jest ddply z pakietu plyr: Roztwór

require(plyr) 
> ddply(dat, .(group), mutate, new_value = log2(value/value[1])) 
    group day  value new_value 
1 g1 0 0.50747820 0.00000000 
2 g1 2 0.30676851 -0.72619548 
3 g1 4 0.42690767 -0.24942179 
4 g2 0 0.69310208 0.00000000 
5 g2 2 0.08513597 -3.02522716 
6 g2 4 0.22543662 -1.62034599 
7 g3 0 0.27453052 0.00000000 
8 g3 2 0.27230507 -0.01174274 
9 g3 4 0.61582931 1.16556397 
+0

Wystarczy ustawić mnie na zasadzie mutate-aranżuj-podsumuj-unrowname-str_replace-count łańcuch uczenia się i odkrywania :) Dzięki – nachocab

+0

'plyr'jest całkiem niesamowite :) –

3

Podstawa:

> res <- do.call(rbind,by(dat,dat$group,function(x) log2(x$value/x$value[x$day==0]))) 
> res 

    [,1]  [,2]  [,3] 
g1 0 -1.6496538 -2.3673937 
g2 0 0.3549090 0.4537402 
g3 0 -0.9423506 1.4603706 

> colnames(res) <- c("day_0","log_ratio_day_2_day_0","log_ratio_day_4_day_0") 
> res 

    day_0 log_ratio_day_2_day_0 log_ratio_day_4_day_0 
g1  0   -1.6496538   -2.3673937 
g2  0    0.3549090    0.4537402 
g3  0   -0.9423506    1.4603706 
5

data.table rozwiązanie dla kodowania elegancji i pamięci efektywność

library(data.table) 

DT <- data.table(dat) 

# assign within DT by reference 

DT[, new_value := log2(value/value[day == 0]), by = group] 

Albo można użyć joins i keys i by-without-by

DTb <- data.table(dat) 

setkey(DTb, group) 

# val0 contains just those records for day 0 
val0 <- DTb[day==0] 

# the i.value refers to value from the i argument 
# which is in this case `val0` and thus the value for 
# day = 0 
DTb[val0, value := log2(value/i.value)] 

Oba te rozwiązania zrobić nie wymagać, aby posortować według day aby value będzie pierwszy (lub jakaś konkretna) elementem.


EDIT

Docuementation dla i. składnia

********************************************** 
    **           ** 
    ** CHANGES IN DATA.TABLE VERSION 1.7.10 ** 
    **           ** 
    ********************************************** 
    NEW FEATURES 

o New function setcolorder() reorders the columns by name 
    or by number, by reference with no copy. This is (almost) 
    infinitely faster than DT[,neworder,with=FALSE]. 

o The prefix i. can now be used in j to refer to join inherited 
    columns of i that are otherwise masked by columns in x with 
    the same name. 
+0

Nie jestem zaznajomiony z' i.value'. Czy możesz wyjaśnić lub wskazać mi odpowiednie dokumenty? – GSee

+0

@GSee, wyjaśniłem to. Teraz szukam odpowiednich dokumentów. – mnel

+2

@GZobacz, i dodano link do ogłoszenia NEWS o składni "i.value". – mnel

1

używa ave w rdzeniu R:

transform(dat, value0 = ave(value, group, FUN = function(x) log2(x/x[1])))