
Reorganizace datových tabulek
V analýze dat se v případě výskytu opakovaných měření (pozorování v čase, případně technické replikáty) setkáte s konceptem "široká vs. dlouhá data".
- široká data - pokud každé opakování reprezentuje samostatný sloupec
- dlouhá data - pokud každé opakování reprezentuje samostatný řádek
Představme si například měření nejakého krevního parametru x u pacienta v čase 0, 12 a 24 hodin od začátku léčby.
Datová tabulka těchto měření bude ve formátu "širokém" vypadat asi takhle:
> set.seed(12)
> mojedata <- data.frame (pacient=c("P1", "P2", "P3", "P4", "P5"), x.T0 = rnorm(5), x.T12 = rnorm(5), x.T24 = rnorm(5))
> mojedata
pacient x.T0 x.T12 x.T24
1 P1 -1.4805676 -0.2722960 -0.77771958
2 P2 1.5771695 -0.3153487 -1.29388230
3 P3 -0.9567445 -0.6282552 -0.77956651
4 P4 -0.9200052 -0.1064639 0.01195176
5 P5 -1.9976421 0.4280148 -0.15241624
Mnoho funkcí ale vyžaduje, aby byla data seřazena ve formátu dvou sloupců, z nichž první obsahuje hodnoty a další kategorie - to jsou tzv. dlouhá data. Tento formát můžeme vytvořit pomocí funkce stack():
> sdat <- stack(mojedata)
Warning message:
In stack.data.frame(mojedata) : non-vector columns will be ignored
Funkce proměnila pouze numerické sloupce, první sloupec proto ignorovala a vypsala upozorňení.
> sdat
values ind
1 -1.48056759 x.T0
2 1.57716947 x.T0
3 -0.95674448 x.T0
4 -0.92000525 x.T0
5 -1.99764210 x.T0
6 -0.27229604 x.T12
7 -0.31534871 x.T12
8 -0.62825524 x.T12
9 -0.10646388 x.T12
10 0.42801480 x.T12
11 -0.77771958 x.T24
12 -1.29388230 x.T24
13 -0.77956651 x.T24
14 0.01195176 x.T24
15 -0.15241624 x.T24
V případě, že náš datový soubor obsahuje i numerické sloupce které nechceme transformovat (například věk pacienta), určíme ty pro transorfmaci pomocí parametru select:
> mojedata$vek <- c(30,45,53,48,60)
> sdat2 <- stack(mojedata, select = names(mojedata)[-c(1,5)])
> sdat2
values ind
1 -1.48056759 x.T0
2 1.57716947 x.T0
3 -0.95674448 x.T0
4 -0.92000525 x.T0
5 -1.99764210 x.T0
6 -0.27229604 x.T12
7 -0.31534871 x.T12
8 -0.62825524 x.T12
9 -0.10646388 x.T12
10 0.42801480 x.T12
11 -0.77771958 x.T24
12 -1.29388230 x.T24
13 -0.77956651 x.T24
14 0.01195176 x.T24
15 -0.15241624 x.T24
Funkce unstack() data převede na původní formát, ale pozor, již zde nenalezneme ty parametry, které jsme první proměnou ztratili (v našem případě sloupec se jménem pacienta):
> unstack(sdat2)
x.T0 x.T12 x.T24
1 -1.4805676 -0.2722960 -0.77771958
2 1.5771695 -0.3153487 -1.29388230
3 -0.9567445 -0.6282552 -0.77956651
4 -0.9200052 -0.1064639 0.01195176
5 -1.9976421 0.4280148 -0.15241624
Dalším způsobem je použít funkci melt() z balíku reshape.
> melt(mojedata, id.vars=c("pacient","vek"))
pacient vek variable value
1 P1 30 x.T0 -1.48056759
2 P2 45 x.T0 1.57716947
3 P3 53 x.T0 -0.95674448
4 P4 48 x.T0 -0.92000525
5 P5 60 x.T0 -1.99764210
6 P1 30 x.T12 -0.27229604
7 P2 45 x.T12 -0.31534871
8 P3 53 x.T12 -0.62825524
9 P4 48 x.T12 -0.10646388
10 P5 60 x.T12 0.42801480
11 P1 30 x.T24 -0.77771958
12 P2 45 x.T24 -1.29388230
13 P3 53 x.T24 -0.77956651
14 P4 48 x.T24 0.01195176
15 P5 60 x.T24 -0.15241624
Zpětně data proměníme v široký formát funkcí cast():
> cast(melt(mojedata, id.vars=c("pacient","vek")))
pacient vek x.T0 x.T12 x.T24
1 P1 30 -1.4805676 -0.2722960 -0.77771958
2 P2 45 1.5771695 -0.3153487 -1.29388230
3 P3 53 -0.9567445 -0.6282552 -0.77956651
4 P4 48 -0.9200052 -0.1064639 0.01195176
5 P5 60 -1.9976421 0.4280148 -0.15241624
Představme si, že neměříme pouze jednu, ale dvě proměnné v čase. Funkce stack() nebo melt() jsou omezeny, protože neumí rozlišit více proměnných.
> set.seed(123)
> mojedata$y.T0 <- rnorm(5); mojedata$y.T12 <- rnorm(5); mojedata$y.T24 <- rnorm(5)
Přeměna dat širokých na dlouhá se pak provede pomocí funkce reshape(). Její parametry jsou:
data - datová tabulka, která se má změnit
idvar - vektor názvů proměnných, které se mají opakovat (v našem případě věk a jméno pacienta)
varying - které proměnné dlouhého formátu třeba přeuspořádat do širokého formátu
direction - který směr transformace požadujeme
> mojedatares <- reshape(data = mojedata, idvar = c("pacient","vek"), varying = c("x.T0","y.T0","x.T12","y.T12","x.T24","y.T24"), direction = "long")
> mojedatares
pacient vek time x y
P1.30.T0 P1 30 T0 -1.48056759 -0.56047565
P2.45.T0 P2 45 T0 1.57716947 -0.23017749
P3.53.T0 P3 53 T0 -0.95674448 1.55870831
P4.48.T0 P4 48 T0 -0.92000525 0.07050839
P5.60.T0 P5 60 T0 -1.99764210 0.12928774
P1.30.T12 P1 30 T12 -0.27229604 1.71506499
P2.45.T12 P2 45 T12 -0.31534871 0.46091621
P3.53.T12 P3 53 T12 -0.62825524 -1.26506123
P4.48.T12 P4 48 T12 -0.10646388 -0.68685285
P5.60.T12 P5 60 T12 0.42801480 -0.44566197
P1.30.T24 P1 30 T24 -0.77771958 1.22408180
P2.45.T24 P2 45 T24 -1.29388230 0.35981383
P3.53.T24 P3 53 T24 -0.77956651 0.40077145
P4.48.T24 P4 48 T24 0.01195176 0.11068272
P5.60.T24 P5 60 T24 -0.15241624 -0.55584113
Chceme-li upravit data do širokého formátu, použijeme stejnou funkci, ale definujeme jiné parametry:
v.names - které proměnné dlouhého formátu třeba uspořádat do širokého formátu (x,y)
timevar - proměnná označující opakování (time)
> reshape(data = mojedatares, idvar = c("pacient","vek"), v.names = c("x","y"), direction = "wide", timevar="time")
pacient vek x.T0 y.T0 x.T12
P1.30.T0 P1 30 -1.4805676 -0.56047565 -0.2722960
P2.45.T0 P2 45 1.5771695 -0.23017749 -0.3153487
P3.53.T0 P3 53 -0.9567445 1.55870831 -0.6282552
P4.48.T0 P4 48 -0.9200052 0.07050839 -0.1064639
P5.60.T0 P5 60 -1.9976421 0.12928774 0.4280148
y.T12 x.T24 y.T24
P1.30.T0 1.7150650 -0.77771958 1.2240818
P2.45.T0 0.4609162 -1.29388230 0.3598138
P3.53.T0 -1.2650612 -0.77956651 0.4007715
P4.48.T0 -0.6868529 0.01195176 0.1106827
P5.60.T0 -0.4456620 -0.15241624 -0.5558411
Seřazení probíhá s využitím vektorů a indexace.
Seřaďme náš soubor mojedata podle věku pacientů od nejmladšího po nejstaršího:
> mojedata[order(mojedata$vek),]
pacient x.T0 x.T12 x.T24 vek y.T0
1 P1 -1.4805676 -0.2722960 -0.77771958 30 -0.56047565
2 P2 1.5771695 -0.3153487 -1.29388230 45 -0.23017749
4 P4 -0.9200052 -0.1064639 0.01195176 48 0.07050839
3 P3 -0.9567445 -0.6282552 -0.77956651 53 1.55870831
5 P5 -1.9976421 0.4280148 -0.15241624 60 0.12928774
y.T12 y.T24
1 1.7150650 1.2240818
2 0.4609162 0.3598138
4 -0.6868529 0.1106827
3 -1.2650612 0.4007715
5 -0.4456620 -0.5558411
Nyní seřaďme podle věku a podle proměnné x.T0 - také od největších hodnot po nejmenší:
> mojedata[order(mojedata$vek, mojedata$x.T0),]
pacient x.T0 x.T12 x.T24 vek y.T0
1 P1 -1.4805676 -0.2722960 -0.77771958 30 -0.56047565
2 P2 1.5771695 -0.3153487 -1.29388230 45 -0.23017749
4 P4 -0.9200052 -0.1064639 0.01195176 48 0.07050839
3 P3 -0.9567445 -0.6282552 -0.77956651 53 1.55870831
5 P5 -1.9976421 0.4280148 -0.15241624 60 0.12928774
y.T12 y.T24
1 1.7150650 1.2240818
2 0.4609162 0.3598138
4 -0.6868529 0.1106827
3 -1.2650612 0.4007715
5 -0.4456620 -0.5558411