将data.frame展开为长格式并增加值
我想将我的数据从短格式转换为长格式,我想有一种简单的方法可以做到这一点(可能使用Reforme2、plyr、dplyr等) 例如,我有:将data.frame展开为长格式并增加值,r,dplyr,R,Dplyr,我想将我的数据从短格式转换为长格式,我想有一种简单的方法可以做到这一点(可能使用Reforme2、plyr、dplyr等) 例如,我有: foo <- data.frame(id = 1:5, y = c(0, 1, 0, 1, 0), time = c(2, 3, 4, 2, 3)) id y time 1 0 2 2 1 3 3 0 4 4 1 2 5 0 3 作为奖励,我还想对变量“y”进行某种递增,其
foo <- data.frame(id = 1:5,
y = c(0, 1, 0, 1, 0),
time = c(2, 3, 4, 2, 3))
id y time
1 0 2
2 1 3
3 0 4
4 1 2
5 0 3
作为奖励,我还想对变量“y”进行某种递增,其中,对于y=1的ID,y设置为0,直到“time”的最大值。也就是说,我想制作:
id y time
1 0 1
1 0 2
2 1 1
2 1 2
2 1 3
3 0 1
3 0 2
3 0 3
3 0 4
4 1 1
4 1 2
5 0 1
5 0 2
5 0 3
id y time
1 0 1
1 0 2
2 0 1
2 0 2
2 1 3
3 0 1
3 0 2
3 0 3
3 0 4
4 0 1
4 1 2
5 0 1
5 0 2
5 0 3
这似乎是dplyr可能已经做过的事情,但我只是不知道去哪里看。无论如何,任何避免循环的解决方案都是有帮助的。您可以使用适当的
id
和time
列为长格式创建一个新的数据帧,然后将其与原始数据帧合并。这将为不匹配的值留下NA
,然后可以用0
替换:
merge(foo,
with(foo,
data.frame(id=rep(id,time), time=sequence(time))
),
all.y=TRUE
)
## id time y
## 1 1 1 NA
## 2 1 2 0
## 3 2 1 NA
## 4 2 2 NA
## 5 2 3 1
## 6 3 1 NA
## 7 3 2 NA
## 8 3 3 NA
## 9 3 4 0
## 10 4 1 NA
## 11 4 2 1
## 12 5 1 NA
## 13 5 2 NA
## 14 5 3 0
类似的合并适用于第一次扩展。合并foo
,不使用time
列,并使用与上述相同的已创建数据帧:
merge(foo[c('id','y')],
with(foo,
data.frame(id=rep(id,time), time=sequence(time))
)
)
## id y time
## 1 1 0 1
## 2 1 0 2
## 3 2 1 1
## 4 2 1 2
## 5 2 1 3
## 6 3 0 1
## 7 3 0 2
## 8 3 0 3
## 9 3 0 4
## 10 4 1 1
## 11 4 1 2
## 12 5 0 1
## 13 5 0 2
## 14 5 0 3
无需在后一个表达式中指定
all
(或all.y
),因为每个匹配的id
值都有多个time
值,并且这些值是展开的。在前一种情况下,time
值与两个数据帧匹配,在不指定all
(或all.y
)的情况下,您将获得原始数据。初始扩展可通过以下方式实现:
newdat <- transform(
foo[rep(rownames(foo),foo$time),],
time = sequence(foo$time)
)
# id y time
#1 1 0 1
#1.1 1 0 2
#2 2 1 1
#2.1 2 1 2
#2.2 2 1 3
# etc
使用dplyr(和magritte,清晰易读):
希望对您有所帮助如果您愿意使用“data.table”,您可以尝试:
library(data.table)
fooDT <- as.data.table(foo)
fooDT[, list(time = sequence(time)), by = list(id, y)]
# id y time
# 1: 1 0 1
# 2: 1 0 2
# 3: 2 1 1
# 4: 2 1 2
# 5: 2 1 3
# 6: 3 0 1
# 7: 3 0 2
# 8: 3 0 3
# 9: 3 0 4
# 10: 4 1 1
# 11: 4 1 2
# 12: 5 0 1
# 13: 5 0 2
# 14: 5 0 3
@MatthewLundberg—
cumsum(foo$time)
将始终给出扩展数据中组的最后一行。对y==1
进行子集设置,并将其反转,将每组中最后一行之前的所有行设置为0.+1。我没有做任何测量,但这看起来比合并更有效。@MatthewLundberg,现在选项中有“dplyr”和“data.table”解决方案,谁来做基准测试;-)实际上,通过一些快速测试,这项功能的性能非常好。您可以尝试foo[rep(1:nrow(foo),foo$time),]%%>%groupby(id)%%>%mutate(time=1:n(),y=replace(y,!!y,c(rep(0,n()-1),1))
within(
foo[rep(rownames(foo),foo$time),],
{
time <- sequence(foo$time)
y[-cumsum(foo$time)] <- 0
}
)
library(magrittr)
library(dplyr)
foo[rep(1:nrow(foo), foo$time), ] %>%
group_by(id) %>%
mutate(y = !duplicated(y, fromLast = TRUE),
time = 1:n())
library(data.table)
fooDT <- as.data.table(foo)
fooDT[, list(time = sequence(time)), by = list(id, y)]
# id y time
# 1: 1 0 1
# 2: 1 0 2
# 3: 2 1 1
# 4: 2 1 2
# 5: 2 1 3
# 6: 3 0 1
# 7: 3 0 2
# 8: 3 0 3
# 9: 3 0 4
# 10: 4 1 1
# 11: 4 1 2
# 12: 5 0 1
# 13: 5 0 2
# 14: 5 0 3
fooDT[, list(time = sequence(time)),
by = list(id, y)][, y := {y[1:(.N-1)] <- 0; y},
by = id][]
# id y time
# 1: 1 0 1
# 2: 1 0 2
# 3: 2 0 1
# 4: 2 0 2
# 5: 2 1 3
# 6: 3 0 1
# 7: 3 0 2
# 8: 3 0 3
# 9: 3 0 4
# 10: 4 0 1
# 11: 4 1 2
# 12: 5 0 1
# 13: 5 0 2
# 14: 5 0 3
fooDT[, list(time=seq_len(time)), by=list(id,y)][y == 1,
y := c(rep.int(0, .N-1L), 1), by=id][]