在满足条件时向前传送data.table列值

时间:2017-04-17 21:35:48

标签: r data.table

我有一个包含两列的data.table。

public class ChildTable : EntityBase {
    private string _someCategory;

    [Key]
    [Column(name: "CHILD_ID")]
    public override int Id { get; protected set; }

    [Column(name: "SOME_CATEGORY")]
    public string SomeCategory {
        get { return _someCategory; }
        set { _someCategory = value ?? ParentTable.SomeCategory; }
    }

    [ForeignKey("ParentTable")]
    [Column(name: "PARENT_ID")]
    public int ParentTableId { get; set; }

    public virtual ParentTable ParentTable { get; set; }
}

我需要发生的是任何时候列a == -1我需要将列b中的值结转到列a == -1的下一行之前的位置。如果没有-1s,那么b列中的值需要继续,直到data.table结束

这是我希望的结果

dt = data.table(a = c(0,0,-1,rep(0,3),-1,1), b = c(1,2,3,2,4,2,4,5))
> dt
    a b
1:  0 1
2:  0 2
3: -1 3
4:  0 2
5:  0 4
6:  0 2
7: -1 4
8:  1 5

2 个答案:

答案 0 :(得分:3)

好吧,这并不像我原先想象的那么困难。如有必要,我可以删除这个问题,但我还没有在stackoverflow上发现任何类似内容,所以我现在就发布我的解决方案。

第一个解决方案存在问题。这个实际上做了我期望的,但我确信有更快的方法来计算它。

library(data.table)
dt = data.table(a = c(0,0,-1,rep(0,3),-1,1), b = c(1,2,3,2,4,2,4,5))

indices = which(dt$a == -1)
values = dt$b[indices]

dt[ , "tmp" := findInterval(1:nrow(dt), indices)]

dt$b = mapply(function(tmp, b){
                      if(tmp == 0){
                        return(b)
                      }else{
                        return(values[tmp])
                      }
                    }, dt$tmp, dt$b)

dt[ , "tmp" := NULL]

> dt
    a b
1:  0 1
2:  0 2
3: -1 3
4:  0 3
5:  0 3
6:  0 3
7: -1 4
8:  1 4

感谢@Frank提供更好的解决方案

dt[, tmp := cumsum(a==-1)][tmp > 0L, b := first(b), by=tmp][, tmp := NULL ]

答案 1 :(得分:2)

在基地R中也许是这样的事情:

x <- c(which(dt==-1), nrow(dt)+1)
#[1] 3 7 9
dt[x[1]:nrow(dt),]$b <- rep(dt$b[head(x,-1)], diff(x))

#   a b
#1:  0 1
#2:  0 2
#3: -1 3
#4:  0 3
#5:  0 3
#6:  0 3
#7: -1 4
#8:  1 4