2016-06-06 8 views
2

Stellen wir Daten über langes Format wie diese:R: Von Langformat-Tabelle "diagonal" Format

ID T  X  Y  Z 
1 1  x1 y1 z1 
1 2  x2 y2 z2 
1 3  x3 y3 z3 
2 1  .... 

Mit mehreren Eingangsgrößen (hier nur X und Y) und Ausgangsgrößen (hier Z).
Ich habe nur die ersten Zeilen gezeigt, die zu und 1 gehören, aber wir hätten mehr Daten darunter.

Wie kann ich es in dieses Format umwandeln:

1 1  x1    y1     z1 
1 2  x1 x2   y1 y2    z2 
1 3  x1 x2 x3 y1 y2 y3  z3 
2 1  ...    .... 

Wo der fehlende Raum NAs o 0.
Jede Lösung mit data.table, dplyr oder Base R wäre, ist willkommen.

Der Grund, warum ich tue es, weil ich so zu einer Regression will:

y1 = a10 + a11·X1 
y2 = a20 + a21·X1 + a22·X2 
y3 = a30 + a31·X1 + a32·X2 + a33·X3 

Wenn Sie ein reproduzierbares Beispiel wollen:

set.seed(1) 
ID <- rep(1:4,each=4) 
XX <- round(runif(16),3) 
YY <- round(runif(16),3) 
TT <- rep(1:4, 4) 
ZZ <- ave(XX*TT,ID, FUN = cumsum) 
data.frame(ID,TT,XX, YY, ZZ) 

    ID TT XX YY ZZ 
1 1 1 0.266 0.718 0.266 
2 1 2 0.372 0.992 1.010 
3 1 3 0.573 0.380 2.729 
4 1 4 0.908 0.777 6.361 
5 2 1 0.202 0.935 0.202 
6 2 2 0.898 0.212 1.998 
7 2 3 0.945 0.652 4.833 
8 2 4 0.661 0.126 7.477 
9 3 1 0.629 0.267 0.629 
10 3 2 0.062 0.386 0.753 
11 3 3 0.206 0.013 1.371 
12 3 4 0.177 0.382 2.079 
13 4 1 0.687 0.870 0.687 
14 4 2 0.384 0.340 1.455 
15 4 3 0.770 0.482 3.765 
16 4 4 0.498 0.600 5.757 

Was passiert, wenn ich das Ergebnis wollte wie?

1 1  x1    y1     z1 
1 2  x2 x1   y2 y1    z2 
1 3  x3 x2 x1 y3 y2 y1  z3 
2 1  ...    .... 
+0

Ich denke, dass es mit Basis R aus dem Wide-Format erfolgen kann, indem jede Zeile repliziert und später jede Spalte eine andere Nummer verschiebt ... – skan

+0

In Bezug auf die letzte Änderung: Das ist einfach wi th data.table :: Verschiebung. – Roland

Antwort

2

Rolands Antwort ist gut. Sie könnten auch dcast und cumsum verwenden.

Es klingt kompliziert, aber es ist tatsächlich einfacher, dass es nicht mehr Anrufungen der Dreiecks Funktion erfordern, so ist es einfacher, eine beliebige Anzahl von Eingangsvariablen maßstab .:

df <- data.frame(ID, TT, XX, YY, ZZ) 
library(data.table) 
setDT(df) 

input_vars <- c("XX","YY") 

dt2 <- dcast(df, ID + TT + ZZ ~ TT, value.var=input_vars, fill=0) 
head(dt2) 
# ID TT ZZ XX_1 XX_2 XX_3 XX_4 YY_1 YY_2 YY_3 YY_4 
# 1: 1 1 0.266 0.266 0.000 0.000 0.000 0.718 0.000 0.00 0.000 
# 2: 1 2 1.010 0.000 0.372 0.000 0.000 0.000 0.992 0.00 0.000 
# 3: 1 3 2.729 0.000 0.000 0.573 0.000 0.000 0.000 0.38 0.000 
# 4: 1 4 6.361 0.000 0.000 0.000 0.908 0.000 0.000 0.00 0.777 
# 5: 2 1 0.202 0.202 0.000 0.000 0.000 0.935 0.000 0.00 0.000 
# 6: 2 2 1.998 0.000 0.898 0.000 0.000 0.000 0.212 0.00 0.000 

# now we just need to get rid of the trailing 0's 
# This can be done with a cumulative sum with a keyby ID 
cum_cols <- setdiff(names(dt2), c("ID","TT","ZZ")) 

dt2[, (cum_cols) := lapply(.SD, cumsum), 
    .SDcols = cum_cols, keyby = ID] 

head(dt2) 
# looks like: 
# ID TT ZZ XX_1 XX_2 XX_3 XX_4 YY_1 YY_2 YY_3 YY_4 
# 1: 1 1 0.266 0.266 0.000 0.000 0.000 0.718 0.000 0.00 0.000 
# 2: 1 2 1.010 0.266 0.372 0.000 0.000 0.718 0.992 0.00 0.000 
# 3: 1 3 2.729 0.266 0.372 0.573 0.000 0.718 0.992 0.38 0.000 
# 4: 1 4 6.361 0.266 0.372 0.573 0.908 0.718 0.992 0.38 0.777 
# 5: 2 1 0.202 0.202 0.000 0.000 0.000 0.935 0.000 0.00 0.000 
# 6: 2 2 1.998 0.202 0.898 0.000 0.000 0.935 0.212 0.00 0.000 
+0

Schön. Was ist, wenn das Ergebnis, das ich wollte, so war, wie ich es bei meinem Beitrag hinzugefügt habe? Ich denke, das wird erreicht, indem man die letzte Zeile in deinem Code verändert (etwas rückgängig macht), aber es ist das schwierigste. – skan

+0

@skann, wie schlecht brauchst du das Ergebnis, um ein 'dat.frame' zu ​​sein? Es scheint, als wäre eine generische Liste die logischere Wahl für das, was Sie versuchen zu tun, da die Spaltenindizes nicht mehr aussagekräftig sind. – C8H10N4O2

+0

Später werde ich es verwenden, um eine Regressionslinie mit wiederholten Takten einzufügen. Vielleicht ist mein Weg nicht in Ordnung. Ich will, dass ZZ für T = 1 nur von XX1 abhängt, dass ZZ für T = 2 nur von XX1 und XX2 abhängt, und so weiter. Ich meine ZZ zu einer bestimmten Zeit hängt von XX zu dieser Zeit und vorherigen XX. – skan

3

Erstellen Sie eine Funktion, die das obere Dreieck auf Null eine Matrix gefüllt zeilenweise mit den Werten und setzt erstellt: Sie können shift verwenden

fun <- function(x) { 
    m <- matrix(x, length(x), length(x), byrow = TRUE) 
    m[upper.tri(m)] <- 0 
    as.data.frame(m) 
} 

#test it 
fun(1:4) 
# V1 V2 V3 V4 
#1 1 0 0 0 
#2 1 2 0 0 
#3 1 2 3 0 
#4 1 2 3 4 

library(data.table) #for its by 
setDT(DF) 
DF[, paste0("x", 1:4) := fun(XX), by = ID] 
DF[, paste0("y", 1:4) := fun(YY), by = ID] 
# ID TT XX YY ZZ x1 x2 x3 x4 y1 y2 y3 y4 
# 1: 1 1 0.266 0.718 0.266 0.266 0.000 0.000 0.000 0.718 0.000 0.000 0.000 
# 2: 1 2 0.372 0.992 1.010 0.266 0.372 0.000 0.000 0.718 0.992 0.000 0.000 
# 3: 1 3 0.573 0.380 2.729 0.266 0.372 0.573 0.000 0.718 0.992 0.380 0.000 
# 4: 1 4 0.908 0.777 6.361 0.266 0.372 0.573 0.908 0.718 0.992 0.380 0.777 
# 5: 2 1 0.202 0.935 0.202 0.202 0.000 0.000 0.000 0.935 0.000 0.000 0.000 
# 6: 2 2 0.898 0.212 1.998 0.202 0.898 0.000 0.000 0.935 0.212 0.000 0.000 
# 7: 2 3 0.945 0.652 4.833 0.202 0.898 0.945 0.000 0.935 0.212 0.652 0.000 
# 8: 2 4 0.661 0.126 7.477 0.202 0.898 0.945 0.661 0.935 0.212 0.652 0.126 
# 9: 3 1 0.629 0.267 0.629 0.629 0.000 0.000 0.000 0.267 0.000 0.000 0.000 
#10: 3 2 0.062 0.386 0.753 0.629 0.062 0.000 0.000 0.267 0.386 0.000 0.000 
#11: 3 3 0.206 0.013 1.371 0.629 0.062 0.206 0.000 0.267 0.386 0.013 0.000 
#12: 3 4 0.177 0.382 2.079 0.629 0.062 0.206 0.177 0.267 0.386 0.013 0.382 
#13: 4 1 0.687 0.870 0.687 0.687 0.000 0.000 0.000 0.870 0.000 0.000 0.000 
#14: 4 2 0.384 0.340 1.455 0.687 0.384 0.000 0.000 0.870 0.340 0.000 0.000 
#15: 4 3 0.770 0.482 3.765 0.687 0.384 0.770 0.000 0.870 0.340 0.482 0.000 
#16: 4 4 0.498 0.600 5.757 0.687 0.384 0.770 0.498 0.870 0.340 0.482 0.600 

Für den anderen Ergebnis:

DF[, paste0("x", 1:4) := shift(XX, 0:3, fill = 0), by = ID] 
# ID TT XX YY ZZ x1 x2 x3 x4 
# 1: 1 1 0.266 0.718 0.266 0.266 0.000 0.000 0.000 
# 2: 1 2 0.372 0.992 1.010 0.372 0.266 0.000 0.000 
# 3: 1 3 0.573 0.380 2.729 0.573 0.372 0.266 0.000 
# 4: 1 4 0.908 0.777 6.361 0.908 0.573 0.372 0.266 
# 5: 2 1 0.202 0.935 0.202 0.202 0.000 0.000 0.000 
# 6: 2 2 0.898 0.212 1.998 0.898 0.202 0.000 0.000 
# 7: 2 3 0.945 0.652 4.833 0.945 0.898 0.202 0.000 
# 8: 2 4 0.661 0.126 7.477 0.661 0.945 0.898 0.202 
# 9: 3 1 0.629 0.267 0.629 0.629 0.000 0.000 0.000 
#10: 3 2 0.062 0.386 0.753 0.062 0.629 0.000 0.000 
#11: 3 3 0.206 0.013 1.371 0.206 0.062 0.629 0.000 
#12: 3 4 0.177 0.382 2.079 0.177 0.206 0.062 0.629 
#13: 4 1 0.687 0.870 0.687 0.687 0.000 0.000 0.000 
#14: 4 2 0.384 0.340 1.455 0.384 0.687 0.000 0.000 
#15: 4 3 0.770 0.482 3.765 0.770 0.384 0.687 0.000 
#16: 4 4 0.498 0.600 5.757 0.498 0.770 0.384 0.687 

Allerdings habe ich den Eindruck, dass wir hier eine XY problem haben. Wenn Sie Ihr tatsächliches Ziel (in einer neuen Frage mit einem reproduzierbaren Beispiel) erklärten, könnten wahrscheinlich bessere Wege vorgeschlagen werden.

1

Wenn jemand interessiert ist, Ich habe meine eigene Antwort für meine las Frage, mit Basis R.

ave(df[rep(names(df[3:5]),each=4)], df$ID, FUN=function(x) mapply(
function(y,z) c(rep(0,z),head(y,length(y)-z)),x,rep(0:3,3))) 
+0

Es gibt keine 'shift' Funktion in der Basis R. (Und das ist sehr ineffizient.) – Roland

+0

OK, es funktionierte, weil ich andere Bibliotheken geladen hatte. Jetzt ist es völlig unabhängig von ihnen. – skan