首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将data.frame扩展为长格式和增量值

将data.frame扩展为长格式和增量值
EN

Stack Overflow用户
提问于 2014-10-02 09:01:33
回答 4查看 364关注 0票数 3

我想要将我的数据从短格式转换成长格式,我想有一种简单的方法可以做到这一点(可能使用reshape2、plyr、dplyr等?)。

例如,我有:

代码语言:javascript
运行
复制
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

我想将每行扩展/复制n次,其中n是该行在"time“列中的值。但是,我也希望变量"time“从1递增到n。也就是说,我希望生成:

代码语言:javascript
运行
复制
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

作为奖励,我还想对变量"y“进行一种递增,其中对于y= 1的I,y被设置为0,直到"time”的最大值。也就是说,我想要产生:

代码语言:javascript
运行
复制
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已经在做的事情了,但我只是不知道去哪里看。无论如何,任何避免循环的解决方案都是有帮助的。

EN

回答 4

Stack Overflow用户

发布于 2014-10-02 10:00:09

您可以为长格式创建一个具有适当idtime列的新数据框,然后将其与原始数据框合并。这将为不匹配的值保留NA,然后可以用0替换这些值

代码语言:javascript
运行
复制
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

类似的合并适用于第一次扩展。将不带time列的foo与上面创建的数据框合并:

代码语言:javascript
运行
复制
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),因为每个匹配的time值都有多个id值,这些值都被展开了。在前一种情况下,两个数据帧的time值都是匹配的,如果不指定all (或all.y),就会得到原始数据。

票数 3
EN

Stack Overflow用户

发布于 2014-10-02 10:58:31

初始扩展可以通过以下方式实现:

代码语言:javascript
运行
复制
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

要获得完整的解决方案,包括奖励部分,请执行以下操作:

代码语言:javascript
运行
复制
newdat$y[-cumsum(foo$time)] <- 0

#    id y time
#1    1 0    1
#1.1  1 0    2
#2    2 0    1
#2.1  2 0    2
#2.2  2 1    3
#etc

如果您真的很兴奋,您可以使用within一步完成所有这些操作

代码语言:javascript
运行
复制
within(
  foo[rep(rownames(foo),foo$time),],
  {
    time <- sequence(foo$time)
    y[-cumsum(foo$time)] <- 0
  }
)
票数 3
EN

Stack Overflow用户

发布于 2014-10-02 12:15:27

如果你愿意使用"data.table",你可以试试:

代码语言:javascript
运行
复制
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

还有,关于奖金的问题:

代码语言:javascript
运行
复制
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

对于奖金问题,另一个选择是:

代码语言:javascript
运行
复制
fooDT[, list(time=seq_len(time)), by=list(id,y)][y == 1, 
                y := c(rep.int(0, .N-1L), 1), by=id][]
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26152999

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档