将行r的值插入行(r + 1)并将第1行插入到data.table中的多个列的第一行中

时间:2014-05-06 18:58:50

标签: r data.table

给定data.table和指示多个目标列的向量:替换目标列的最有效方法是什么?第1行和第r行的值是否为(r-1)加1?

的值

整个操作应该由一个名为id1的键重复。

原始data.table和目标列看起来像这样

library(data.table)

DT <- data.table(id1=c(1,1,1,2,2,2), id2=c(1,2,3,1,2,3), c1=c(0,1,0,2,1,2), c2=c(0,0,1,1,2,3), c3=c(1,2,2,1,1,1))
setkey(DT,id1,id2)
cnames <- c("c1","c2","c3")

DT
#    id1 id2 c1 c2 c3
# 1:   1   1  0  0  1
# 2:   1   2  1  0  2
# 3:   1   3  0  1  2
# 4:   2   1  2  1  1
# 5:   2   2  1  2  1
# 6:   2   3  2  3  1

这是理想的结果

   # id1 id2 c1 c2 c3
# 1:   1   1  1  1  1      #substituted by 1
# 2:   1   2  1  1  2      # previous row + 1
# 3:   1   3  2  1  3      #        "
# 4:   2   1  1  1  1      # substituted by 1
# 5:   2   2  3  2  2      # previous row + 1
# 6:   2   2  2  3  2      #        "

我知道像DT[,"c1" := c(1,c1[.I-1]+1), by=id1]这样的东西可能有用,但这会带来两个挑战:首先,c1[.I-1]的第一个值没有定义。第二,使用此代码的替换将针对一个clumn执行(此处:&#34; c1&#34;),而我需要对多个列执行替换,在向量&#34; cnames&#34中指示;

谢谢!亚娜

1 个答案:

答案 0 :(得分:3)

最简单的方法是首先为每个组设置第一行到所有0。然后,为每列添加1。这相当于您希望做的事情。以下是我的表现:

setkey(DT, id1)
DT[J(unique(id1)), c(cnames) := list(0L), mult="first"]
DT[, c(cnames) := .SD+1L, .SDcols=cnames]

#    id1 id2 c1 c2 c3
# 1:   1   1  1  1  1
# 2:   1   2  2  1  3
# 3:   1   3  1  2  3
# 4:   2   1  1  1  1
# 5:   2   2  2  3  2
# 6:   2   3  3  4  2

根据OP的评论并编辑问题:

您可以按如下方式完成此操作:首先将行换1列,同时将第一列替换为0&#39; s,然后将1添加到所有列。

DT[, c(cnames) := lapply(.SD, function(x) 
            c(0L, head(x, -1L))), by=id1, .SDcols=cnames]
DT[, c(cnames) := .SD+1L, .SDcols=cnames]

> DT
#    id1 id2 c1 c2 c3
# 1:   1   1  1  1  1
# 2:   1   2  1  1  2
# 3:   1   3  2  1  3
# 4:   2   1  1  1  1
# 5:   2   2  3  2  2
# 6:   2   3  2  3  2

通过查看评论中的问题的另一种变体:

首先将整个数据移动1行,不进行分组,然后将其加1。然后,将每个组的第一行设置为所有1。

setkey(DT, id1)
DT[2:nrow(DT), c(cnames) := head(DT[, cnames, with=FALSE], -1L) + 1L]
DT[J(unique(id1)), c(cnames) := list(1L), mult="first"]