想象一下,我有这样的长格式数据:
ID T X Y Z
1 1 x1 y1 z1
1 2 x2 y2 z2
1 3 x3 y3 z3
2 1 ....
有几个输入变量(这里只有X和Y)和输出变量(这里是Z) 我只展示了第一行,属于和个人1,但我们会在这之下有更多的数据。
如何将其转换为以下格式:
1 1 x1 y1 z1
1 2 x1 x2 y1 y2 z2
1 3 x1 x2 x3 y1 y2 y3 z3
2 1 ... ....
缺失的空间是NAs o。
任何带有data.table,dplyr或base R的解决方案都是受欢迎的。
我这样做的原因是因为我想要这样的回归:
y1 = a10 + a11·X1
y2 = a20 + a21·X1 + a22·X2
y3 = a30 + a31·X1 + a32·X2 + a33·X3
如果您想要一个可重复的示例:
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
如果我想要结果怎么办?
1 1 x1 y1 z1
1 2 x2 x1 y2 y1 z2
1 3 x3 x2 x1 y3 y2 y1 z3
2 1 ... ....
答案 0 :(得分:3)
创建一个函数,该函数创建一个用值逐行填充的矩阵,并将上三角形设置为零:
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
对于其他结果,您可以使用shift
:
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
但是,我得到的印象是我们在这里有一个XY problem。如果你解释了你的实际目标(在一个新的问题中,有一个可重复的例子),可能会提出更好的方法。
答案 1 :(得分:2)
罗兰的答案很好。您还可以使用dcast
和cumsum
。
这听起来很复杂,但它实际上更简单,因为它不需要多次调用三角函数,所以它更容易扩展到任意数量的输入变量。:
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
答案 2 :(得分:1)
如果有人感兴趣的话,我的拉斯问题得到了我自己的答案,基础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)))