如何基于一组不等式约束对data.table进行排序?

时间:2018-10-04 21:54:31

标签: r sorting data.table

我有一组“ x

例如,

library(data.table)
set.seed(0)
ineqs <- unique(data.table(
  X = sample(letters, 10, replace = T),
  Rel = "<",
  Y = sample(letters, 10, replace = T)
))
ineqs
    X Rel Y
 1: x   < b
 2: g   < f
 3: j   < e
 4: o   < r
 5: x   < j
 6: f   < u
 7: x   < m
 8: y   < s
 9: r   < z
10: q   < j

所以,如果我从一个排序字母表开始,

dt <- data.table(Foo = letters)
    Foo
 1:   a
 2:   b
 3:   c
---    
24:   x
25:   y
26:   z

如何调整行顺序以满足我的约束?另外,我可以确定我的约束是 valid (即,没有一个约束相互矛盾)。

2 个答案:

答案 0 :(得分:7)

library(igraph)
g = ineqs[, graph_from_edgelist(cbind(X,Y), directed=TRUE)]
o = names(topo_sort(g))

dt[, v := factor(Foo, levels = o, ordered=TRUE)]
dt[order(v)]


    Foo    v
 1:   x    x
 2:   g    g
 3:   o    o
 4:   y    y
 5:   q    q
 6:   b    b
 7:   m    m
 8:   f    f
 9:   r    r
10:   s    s
11:   j    j
12:   u    u
13:   z    z
14:   e    e
15:   a <NA>
16:   c <NA>
17:   d <NA>
18:   h <NA>
19:   i <NA>
20:   k <NA>
21:   l <NA>
22:   n <NA>
23:   p <NA>
24:   t <NA>
25:   v <NA>
26:   w <NA>
    Foo    v

所有不在ineqs中的术语都排在最后。

如果您的关系图具有周期,则应该在topo_sort中得到警告。这说明您在ineqs中某些术语的任务定义不正确。

答案 1 :(得分:4)

也许我误会了,但这并不是一件小事,不一定有一个唯一的顺序。

让我给你一个例子。考虑条件

    X Rel Y
1: x   < b
2: g   < f

各种订单都是可以想象的

        x < g < f < b
g     < x     <     b   <   f
g     < x     < f < b
g < f < x         < b
        x < g <     b     < f
        x <         b < g < f

所有这些都满足前两行中列出的条件。


我很想知道穷举和粗略的实现方式,我们会预先计算所有可能的排列,然后消除那些不满足成对条件的排列。

为说明起见,我们将仅使用4个字母和成对条件数据的前两行。

这是我的结果:

  1. 首先,我们定义四个字母并使用gtools::permutations计算所有排列。

    char <- c("b", "f", "g", "x")
    
    library(gtools)
    perm <- as.data.frame(permutations(length(char), length(char), char))
    

    有24种可能的排列。

  2. 我们现在读取成对条件数据

    df <- read.table(text =
        "X Rel Y
    x   < b
    g   < f", header = T)
    
    # Convert factors to character vectors
    df[] <- sapply(df, as.character)
    
  3. 我们现在循环抛出排列和成对条件,并标记排列数据中不满足任何成对条件的那些行。

    rmv <- c()
    for (i in 1:nrow(perm)) {
        # Here we loop throw all possible permutations and eliminate those that
        # do not fulfil the pairwise conditions
        for (j in 1:nrow(df)) {
            # Here we loop throw the pairwise conditions
            cond <- eval(parse(text = sprintf("`%s`", df[j, "Rel"])))(
                which(perm[i, ] == df[j, "X"]),
                which(perm[i, ] == df[j, "Y"]))
            if (cond == FALSE) {
                rmv <- c(rmv, i)
                break
            }
        }
    }
    
  4. 然后满足条件的剩余排列就是

    perm[-rmv, ]
    #   V1 V2 V3 V4
    #16  g  f  x  b
    #17  g  x  b  f
    #18  g  x  f  b
    #20  x  b  g  f
    #23  x  g  b  f
    #24  x  g  f  b