与两列连接表一致的顺序事件

时间:2018-10-12 09:59:12

标签: r data.table data-manipulation

我有一个表显示事件之间的连接:

library(data.table)
df = data.table(p1 = c("x0", "x0", "x1", "x2", "x3"),
                p2 = c("x1", "x2", "x3", "x3", "x4"))

这是一个例子:

enter image description here

仅当所有先前事件均已发生时,下一个事件才可能发生。例如,事件x3可能仅在x1和x2之后发生,而与它们的顺序无关。

如何以data.table方式将df表转换为下一个表(所有事件以某种允许的顺序显示):

df_required = data.table(p = c("x0", "x1", "x2", "x3", "x4", 
                               "x0", "x1", "x2", "x3", "x4"),
                         sequence = c(1, 2, 3, 4, 5, 1, 3, 2, 4, 5),
                         group = c(1, 1, 1, 1, 1, 2, 2, 2, 2, 2))

必需的表显示了两个可能的连接组:x0-x1-x2-x3-x4和x0-x2-x1-x3-x4。有两种可能的方式,因为两个值可能立即跟随x0:x1或x2。序列也写在插图的圆圈上方。

2 个答案:

答案 0 :(得分:2)

我之所以发布它,是因为它提供的输出与罗兰兹的建议相同:

(如果没有意义,我会删除它)

数据:

library(data.table)
df = data.table(p1 = c("x0", "x0", "x1", "x2", "x3"),
                p2 = c("x1", "x2", "x3", "x3", "x4"))

代码:

restElements <- setdiff(df$p1, df$p2)
ans <-
    t(do.call(
        expand.grid, c(restElements, unique(split(df$p2,df$p1)))
        ))

group = rep(1:ncol(ans), each = nrow(ans))

p     = c( ans )

sequence = as.numeric(factor(p))

data.table(p, sequence, group)

结果:

#    p sequence group
#1: x0        1     1
#2: x1        2     1
#3: x3        4     1
#4: x4        5     1
#5: x0        1     2
#6: x2        3     2
#7: x3        4     2
#8: x4        5     2

请注意:

  • 确保在设置因子factor(p)时获得正确的顺序。 (默认情况下,因子级别是仅排序的。适用于此示例,可能不适用于其他示例。)

  • 使用igraph方法可能比我的ans更为明智。


因此您可以将两者结合在一起

从@Roland借来的

lvls <- levels(factor(c(df$p1, df$p2)))
library(igraph);
tmp <- lapply(all_shortest_paths(graph_from_data_frame(df), lvls[1], lvls[length(lvls)])$res, as.vector)
ans <- sapply(tmp, function(x) { lvls[x] })

您可以使用此ans。确保以后使用:sequence = as.numeric(factor(p, lvls))

答案 1 :(得分:2)

您可以为每个节点分配一个等级(假设您有a graph for which this makes any sense)...

vdf = data.table(p = sort(unique(unlist(df[, c("p1", "p2")]))))

i = 0L
vdf[, r := 0L]
while (any(vdf[r == i, p] %in% df$p1)){
  vdf[r == i, r := r + !df[.(p), on=.(p1), p %in% setdiff(p1, p2)]]
  i = i + 1L
}

    p r
1: x0 0
2: x1 1
3: x2 1
4: x3 2
5: x4 3

如果有一个独特的第一个事件x0,那么感谢@Roland,这是一种更简单的方法:

library(igraph)
vdf[, r := as.vector(distances(graph_from_data_frame(df), "x0"))]

然后,对于具有多个节点的每个等级,进行所有排列(此处,从Generating all distinct permutations of a list in R借用)...

wdf = vdf[, do.call(cbind, lapply(split(.I, r), function(x) as.data.table(
  gtools::permutations(length(x), length(x), x)
)))]

   0.V1 1.V1 1.V2 2.V1 3.V1
1:    1    2    3    4    5
2:    1    3    2    4    5

wdf中的值是?.I的行号(请参阅vdf),所以...

mdf = melt(wdf[, g := .I], id = "g", value.name = "w")[order(g, variable)]
vdf[mdf$w, .(p, g = mdf$g, r)][, seq := rowid(g)][]

     p g r seq
 1: x0 1 0   1
 2: x1 1 1   2
 3: x2 1 1   3
 4: x3 1 2   4
 5: x4 1 3   5
 6: x0 2 0   1
 7: x2 2 1   2
 8: x1 2 1   3
 9: x3 2 2   4
10: x4 2 3   5

因此g是OP中提到的“组”; r是等级; seq是组中的序列(很有用,因此表的排序是明确的)。


注释。在将等级/深度属性分配给vdf中的每个节点后,我将停止。有关可行的事件序列的所有信息都在此处,但是就计算时间和空间而言,对它们进行枚举(如在OP的输出中)可能非常昂贵,因此应尽可能避免。

共享同一等级的事件x的排列数为factorial(length(x)),例如,如果x的长度为10,则返回的矩阵的维度为{{1} } = 3628800 x10。我的计算机在尝试计算时挂起。