4

我有一个类似于使用以下命令获得的数据表:

dt <- data.table(
  time = 1:8,
  part = rep(c(1, 1, 2, 2), 2),
  type = rep(c('A', 'B'), 4),
  data = rep(c(runif(1), 0), 4))

基本上,这样的表包含两种不同类型的实例(A 或 B)。时间列包含请求到达或离开某个部分的时间戳。如果实例类型为 A,则时间戳说明到达时间(进入),如果类型为 B,则时间戳说明离开时间(退出)。

   time part type      data
1:    1    1    A 0.5842668
2:    2    1    B 0.0000000
3:    3    2    A 0.5842668
4:    4    2    B 0.0000000
5:    5    1    A 0.5842668
6:    6    1    B 0.0000000
7:    7    2    A 0.5842668
8:    8    2    B 0.0000000

我想将A和B实例配对,得到如下数据表:

   part data        enter.time exit.time
1:    1 0.4658239   1          2
2:    1 0.4658239   5          6
3:    2 0.4658239   3          4
4:    2 0.4658239   7          8

我尝试了以下方法:

pair.types <- function(x) {
  a.type <- x[type == 'A']
  b.type <- x[type == 'B']
  return(data.table(
      enter.time = a.type$time,
      exit.time = b.type$time,
      data = a.type$data))
}

dt[, c('enter.time', 'exit.time', 'data') := pair.types(.SD), by = list(part)]

但是,这给了我以下,这不是我想要的:

   time part type      data enter.time exit.time
1:    1    1    A 0.3441592          1         2
2:    2    1    B 0.3441592          5         6
3:    3    2    A 0.3441592          3         4
4:    4    2    B 0.3441592          7         8
5:    5    1    A 0.3441592          1         2
6:    6    1    B 0.3441592          5         6
7:    7    2    A 0.3441592          3         4
8:    8    2    B 0.3441592          7         8

它有点接近,但由于保留了“类型”列,所以有些行是重复的。也许,我可以尝试删除列“时间”和“类型”,然后删除行的后半部分。但是,我不确定这是否适用于所有情况,我想学习一种更好的方法来执行此操作。

4

2 回答 2

3

假设您的数据看起来像您的示例数据:

dt[, list(part = part[1],
          data = data[1],
          enter.time = time[1],
          exit.time = time[2]),
     by = as.integer((seq_len(nrow(dt)) + 1)/2)]
#    by = rep(seq(1, nrow(dt), 2), each = 2)]
#    ^^^ a slightly shorter and a little more readable alternative

这个想法非常简单 - 将行分组为 2 组(这就是by部分),即每个组将是一个 A 和一个 B,然后对于每个组先取第一partdata然后进入和退出时间只是第一和第二time的分别。如果您遵循手动逻辑,这可能就是您执行此操作的方式,使其易于阅读(一旦您对工作原理了解一点点data.table)。

于 2013-04-22T21:23:10.930 回答
2

另一种方式:

setkey(dt, "type")
dt.out <- cbind(dt[J("A"), list(part, data, entry.time = time)][, type := NULL], 
      exit.time = dt[J("B"), list(time)]$time)
#    part      data entry.time exit.time
# 1:    1 0.1294204          1         2
# 2:    2 0.1294204          3         4
# 3:    1 0.1294204          5         6
# 4:    2 0.1294204          7         8

如果你愿意,你现在setkey(dt.out, "part")可以得到相同的订单。


这个想法:你的问题对我来说似乎是一个简单的“重塑”问题。我接近它的方式是首先创建一个键列作为type. 现在,我们可以通过以下方式为键列中的特定值设置 data.table 的子集:dt[J("A")]。这将返回整个data.table. 由于您希望time重命名列,因此我明确提到要使用哪些列进行子集化:

dt[J("A"), list(part, data, entry.time = time)]

当然,这也会返回type我们必须删除的列 (= A)。因此,我添加了一个通过引用[, type := NULL]删除列type

现在我们有了第一部分。我们需要的只是exit.time. 这可以类似地获得:

dt[J("B"), list(time)] # I don't name the column here

但这给出了data.table当您只需要时间列时,可以通过以下方式访问:

dt[J("B"), list(time)]$time

因此,在使用cbind此列时,我exit.time将最终结果命名为:

cbind(dt[J("A"), list(part, data, entry.time = time)][, type := NULL], 
      exit.time = dt[J("B"), list(time)]$time)

希望这可以帮助。

于 2013-04-22T21:29:22.670 回答