在id上有条件地分割时变变量的值序列

时间:2013-01-13 12:54:55

标签: r

在我的分析的数据管理步骤中,我遇到了以下问题。

在实践中,每个id最多记录5次,我有一个感兴趣的时变变量tv = 1, 2, 3, 4。假设我的数据是:

dat <- read.table(text = "

        id      tv    
        1       2
        1       2
        1       1
        1       4
        2       4
        2       1
        2       4
        3       1
        3       2
        3       3
        3       3
        3       2", 

    header=TRUE)  

我需要做的是从tv开始创建两组新的变量,以获得:

   id     tv     tv1   tv2   tv3   tv4   tv5    dur1  dur2  dur3  dur4  dur5 
    1      2      2     1     4     0     0       2     1     1     0     0
    1      2      2     1     4     0     0       2     1     1     0     0
    1      1      2     1     4     0     0       2     1     1     0     0
    1      4      2     1     4     0     0       2     1     1     0     0
    2      4      4     1     4     0     0       1     1     1     0     0
    2      1      4     1     4     0     0       1     1     1     0     0
    2      4      4     1     4     0     0       1     1     1     0     0
    3      1      1     2     3     2     0       1     1     2     1     0
    3      2      1     2     3     2     0       1     1     2     1     0
    3      3      1     2     3     2     0       1     1     2     1     0
    3      3      1     2     3     2     0       1     1     2     1     0
    3      2      1     2     3     2     0       1     1     2     1     0

对于id - tv1中的每个tv5,我们都有tv不同(非重复)记录的有序序列,在dur1 - dur5中,我们有原始数据集dat中各自不同记录的出现次数。

我真的不知道如何继续这里..任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:3)

这应该这样做:

require(plyr)
dat <- structure(list(id = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 
         3L, 3L), tv = c(2L, 2L, 1L, 4L, 4L, 1L, 4L, 1L, 2L, 3L, 3L, 2L
         )), .Names = c("id", "tv"), class = "data.frame", row.names = c(NA, 
         -12L))

out <- ddply(dat, .(id), function(x) {
    this.rle <- rle(x$tv)

    val <- this.rle$values
    val <- c(val, rep(0, 5-length(val)))
    val <- matrix(rep(val,nrow(x)), byrow=T, nrow=nrow(x))
    val <- as.data.frame(val)
    names(val) <- paste("tv", 1:5, sep="")

    len <- this.rle$lengths
    len <- c(len, rep(0, 5-length(len)))
    len <- matrix(rep(len,nrow(x)), byrow=T, nrow=nrow(x))
    len <- as.data.frame(len)
    names(len) <- paste("dur", 1:5, sep="")
    cbind(data.frame(tv=x$tv), val, len)
})

> out
   id tv tv1 tv2 tv3 tv4 tv5 dur1 dur2 dur3 dur4 dur5
1   1  2   2   1   4   0   0    2    1    1    0    0
2   1  2   2   1   4   0   0    2    1    1    0    0
3   1  1   2   1   4   0   0    2    1    1    0    0
4   1  4   2   1   4   0   0    2    1    1    0    0
5   2  4   4   1   4   0   0    1    1    1    0    0
6   2  1   4   1   4   0   0    1    1    1    0    0
7   2  4   4   1   4   0   0    1    1    1    0    0
8   3  1   1   2   3   2   0    1    1    2    1    0
9   3  2   1   2   3   2   0    1    1    2    1    0
10  3  3   1   2   3   2   0    1    1    2    1    0
11  3  3   1   2   3   2   0    1    1    2    1    0
12  3  2   1   2   3   2   0    1    1    2    1    0

答案 1 :(得分:2)

这是一个完全基于R的解决方案。它与@ Arun的答案非常相似,但可能比使用“plyr”更快:

out <- cbind(dat, do.call(
    rbind, 
    lapply(split(dat$tv, dat$id), function(x) {
        OUT <- matrix(0, ncol = 10, nrow = 1)
        T1 <- rle(x)
        OUT[1, seq_along(T1$values)] <- T1$values
        OUT[1, 6:(5+length(T1$lengths))] <- T1$lengths
        colnames(OUT) <- paste(rep(c("tv", "dur"), 
                                   each = 5), 1:5, sep ="")
        OUT[rep(1, length(x)), ]
    })))
out
#    id tv tv1 tv2 tv3 tv4 tv5 dur1 dur2 dur3 dur4 dur5
# 1   1  2   2   1   4   0   0    2    1    1    0    0
# 2   1  2   2   1   4   0   0    2    1    1    0    0
# 3   1  1   2   1   4   0   0    2    1    1    0    0
# 4   1  4   2   1   4   0   0    2    1    1    0    0
# 5   2  4   4   1   4   0   0    1    1    1    0    0
# 6   2  1   4   1   4   0   0    1    1    1    0    0
# 7   2  4   4   1   4   0   0    1    1    1    0    0
# 8   3  1   1   2   3   2   0    1    1    2    1    0
# 9   3  2   1   2   3   2   0    1    1    2    1    0
# 10  3  3   1   2   3   2   0    1    1    2    1    0
# 11  3  3   1   2   3   2   0    1    1    2    1    0
# 12  3  2   1   2   3   2   0    1    1    2    1    0

以下是对正在发生的事情的总结:

  1. split(dat$tv, dat$id)为每个“id”在“tv”中创建一个值列表。

  2. 我们应用匿名函数:

    1. 创建一个零的空行矩阵。我们已经知道我们需要10列。
    2. 存储rle()的输出,因为我们需要“值”和“长度”
    3. 使用基本子集将“值”插入矩阵的前五列,将“length”作为最后五列插入。
    4. 添加列名称
    5. 使用一个小技巧将矩阵“扩展”到指定的行数,在这种情况下,行数与每组的行数相同。
  3. do.call(rbind...将所有矩阵放在一起,按行绑定它们。

  4. cbind(dat...将原始data.frame绑定到步骤1到3的结果。

  5. 同样,从概念上讲,这与Arun的回答非常相似 - rle()的使用可能就是你所缺少的。