创建一个新的因子/变量,其水平基于原始因子水平的“N”个连续出现

时间:2017-08-24 18:01:31

标签: r data.table

我已经开始了一个新项目,其中包含一系列我以前从未做过的数据管理,而且我似乎缺乏技能或适当的搜索条件来查找示例。我有一个非常大的数据集,其中包含分组变量和二进制事件变量。它可以推广到一个工作示例:

library('data.table')
grp <- c("a", "a", "a", "a", "a", "a", "a", "b", "b", "b", "b", "b")
v1 <- c(1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1)
test<-data.frame(grp,v1)
test

   grp v1
1    a  1
2    a  0
3    a  0
4    a  1
5    a  1
6    a  1
7    a  1
8    b  1
9    b  0
10   b  0
11   b  0
12   b  1

我一直在使用data.table在“grp”的唯一级别中将“v1”的条纹标记为具有新的序数数字因子“event”的事件:

setDT(test)
test<-test[, .(v1 = v1, event = rleidv(v1)), by=grp]

    grp v1 event
 1:   a  1     1
 2:   a  0     2
 3:   a  0     2
 4:   a  1     3
 5:   a  1     3
 6:   a  1     3
 7:   a  1     3
 8:   b  1     1
 9:   b  0     2
10:   b  0     2
11:   b  0     2
12:   b  1     3

在实际数据集中,这些“grp”特定事件中的一些非常长,我需要将它们分解为较小的,可变的, n - 有限的事件。例如,我对 n = 2的新变量“sub.event”的所需输出是:

> test
    grp v1 event sub.event
 1:   a  1     1         1
 2:   a  0     2         2
 3:   a  0     2         2
 4:   a  1     3         3
 5:   a  1     3         3
 6:   a  1     3         4
 7:   a  1     3         4
 8:   b  1     1         1
 9:   b  0     2         2
10:   b  0     2         2
11:   b  0     2         3
12:   b  1     3         4

我一直在拉着我的头发试图找到一种方法来做到这一点。看起来很简单,我必须遗漏一些明显的东西。为了方便起见,在确定 n -limited“sub.event”之前,可以将原始变量连接成新变量。

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

这是一种适用于链接的方法。

setDT(test)[, new := rep(1:0, length.out=.N), by=.(grp, rleid(v1))][,
              new := cumsum(new), by=grp]

第一个链返回1s和0s的向量,重复grp - rleid对的长度。链中的下一个链接通过grp。{/ p>与cumsum进行求和

返回

test
    grp v1 new
 1:   a  1   1
 2:   a  0   2
 3:   a  0   2
 4:   a  1   3
 5:   a  1   3
 6:   a  1   4
 7:   a  1   4
 8:   b  1   1
 9:   b  0   2
10:   b  0   2
11:   b  0   3
12:   b  1   4

请注意,如上所述,它不会自动扩展到n&gt; 2.但是,产生它的作品1:0可以写成rep(c(1L, rep(0L, n)), length.out=.N),其中n+1是您想要的重复值的数量。

在这种情况下,代码看起来像

test[, new := rep(c(1L, rep(0L, 2L)), length.out=.N), by=.(grp, rleid(v1))][,
       new := cumsum(new), by=grp]

答案 1 :(得分:2)

有点迂回:

# make counters within v1, grp
test[, v0 := rep(1:.N, each=2, length.out=.N), by=.(rleid(grp, v1))]

# make overall counters
test[, v := .GRP, by=rleid(grp, v1, v0)]

# difference per grp
test[, v := v - first(v) + 1L, by=grp]

# drop internal counter
test[, v0 := NULL ]

    grp v1 v
 1:   a  1 1
 2:   a  0 2
 3:   a  0 2
 4:   a  1 3
 5:   a  1 3
 6:   a  1 4
 7:   a  1 4
 8:   b  1 1
 9:   b  0 2
10:   b  0 2
11:   b  0 3
12:   b  1 4