R 以特定的方式排列数据帧

R 以特定的方式排列数据帧,r,dplyr,R,Dplyr,很抱歉,这个标题不好,但我真的不知道如何简洁地表达它 我正在玩一个数据框,其中一个项目可以是4个类别中的任意一个,而不限于1个。下面是我正在使用的虚拟矩阵的一个示例: ID <- 1:7 A <- c(1,0,0,1,1,0,0) B <- c(0,1,0,0,1,0,1) C <- c(0,0,0,0,0,1,1) D <- c(1,0,1,1,0,0,0) A_B <- (A+B > 0)*1 C_D <- (C+D > 0)*1 Cos

很抱歉,这个标题不好,但我真的不知道如何简洁地表达它

我正在玩一个数据框,其中一个项目可以是4个类别中的任意一个,而不限于1个。下面是我正在使用的虚拟矩阵的一个示例:

ID <- 1:7
A <- c(1,0,0,1,1,0,0)
B <- c(0,1,0,0,1,0,1)
C <- c(0,0,0,0,0,1,1)
D <- c(1,0,1,1,0,0,0)
A_B <- (A+B > 0)*1
C_D <- (C+D > 0)*1
Cost <- c(25, 52, 11, 75, 45, 5, 34)

df <- data.frame(ID, A, B, C, D, A_B, C_D, A_B_C_D = 1, Cost)
df

ID A B C D A_B C_D A_B_C_D Cost
1  1 0 0 1  1   1     1     25
2  0 1 0 0  1   0     1     52
3  0 0 0 1  0   1     1     11
4  1 0 0 1  1   1     1     75
5  1 1 0 0  1   0     1     45
6  0 0 1 0  0   1     1     5
7  0 1 1 0  1   1     1     34
基本上,对角线需要是7个直的,但我想不出如何编程使其正确排序,无论数据集如何。我觉得这应该很容易,但我就是看不到。换位会使它更容易吗


提前感谢。

根据您发布的数据,不可能有唯一的解决方案,因为第1行和第4行具有相同的A到D列序列。否则,使用四位布尔模式似乎是一个简单的练习。我不明白为什么要重复位模式1001,除非这是您在设置示例数据时犯的错误

为了解释为什么我感到困惑,如果第1行和第4行在您建议的顺序中颠倒,那么对角线都是1的要求并没有失效,但它显然与之前的顺序不同:

Order2 <- c(1, 2, 7, 4, 5, 3, 6)
df[Order2,]


   ID A B C D A_B C_D A_B_C_D Cost
    1 1 0 0 1   1   1       1   25
    2 0 1 0 0   1   0       1   52
    7 0 1 1 0   1   1       1   34
    4 1 0 0 1   1   1       1   75
    5 1 1 0 0   1   0       1   45
    3 0 0 0 1   0   1       1   11
    6 0 0 1 0   0   1       1    5

Order2一种方法是使用蛮力,通过获取行排列的所有排列并检查是否满足对角期望:

z <- apply(permute::allPerms(1:7), 1, function(x){
  mat <- as.matrix(df[,2:8])
  if(all(diag(mat[x,]) == rep(1,7))){
    return(df[x,])
  }
  })
要获得第一个匹配置换,可以使用while循环:

perms <- permute::allPerms(1:7)
mat <- as.matrix(df[,2:8])
i <- 1
while (!all(diag(mat[perms[i,],])  == rep(1,7))) {
  i = i+1
}

df[perms[i,],]

#  ID A B C D A_B C_D A_B_C_D Cost
1  1 1 0 0 1   1   1       1   25
2  2 0 1 0 0   1   0       1   52
6  6 0 0 1 0   0   1       1    5
3  3 0 0 0 1   0   1       1   11
4  4 1 0 0 1   1   1       1   75
7  7 0 1 1 0   1   1       1   34
5  5 1 1 0 0   1   0       1   45

perms更多行的逻辑是什么?@akrun只有7行,只是多次迭代:它们是
lpsolve
优化的结果。优化工作使我始终能够做出“正确”的订单,我只需要简化订单。最终输出工作需要正确的顺序。谢谢,是只有一个解决方案,还是可以有多个?如果是后者,你在乎你得到的是哪一个吗?您可能需要实现一个搜索算法,在可能的排列树中遍历,直到找到一个可行的为止。@ClausWilke排序可以有多个解决方案,只要对角线上有一个1,排序就没有关系。另一个算法是我害怕的,哈哈。我希望有一个比我聪明的人能有一个简单的解决方案,但听起来我会着手研究一个算法。谢谢你的帮助谢谢你帮了我!我说“一个可以接受的答案是:”但我应该更清楚,没有唯一的解决方案,只要对角线上填充了1,它就可以工作。话虽如此,我还是要看一看德摩根定理,谢谢你的资源。这很好,谢谢你的帮助。正因为如此,我在更高的层次上理解了
test2
:基本上,您告诉R要做的是尽可能多地进行行组合(特定的顺序存储在
perms
)。然后告诉R根据
perms
中的规范重新组织
df
。一旦所有对角线都等于1,停止循环并按顺序返回
df
。拍摄,我的实际
df
s还有一列,因此它是一个8:8的虚拟矩阵
permute::allPerms
无法处理1:8(“可能的排列数量太大”)
allPerms(1:5)
有119行,
allPerms(1:6)
有719行,
allPerms(1:7)
有5039行,所以我怀疑
allPerms(1:8)
大约有38k行。38000x8矩阵通常适合R,所以我不确定它为什么会卡住。你知道有没有解决办法吗?现在看看CRAN@很抱歉给你发了垃圾邮件,但我想让你知道我在你搜索之前就知道了。添加
ctrl@CoolGuyHasChillDay test和test2的区别在于,在第一个函数中,R测试所有置换,而在第二个函数中,R测试直到找到第一个匹配,出于您的目的,它会更好,因为速度更快,因为看起来测试部分比进行置换花费的时间要多得多。我很高兴你解决了这个问题!问题9!应该也行,但是10!这可能是不可能的。我还在考虑其他的解决方案,如果我发现一些值得称赞的东西,我会更新帖子。
z <- Filter(Negate(is.null), z)
length(z) #88

z[[5]] #random solution
#output

  ID A B C D A_B C_D A_B_C_D Cost
1  1 1 0 0 1   1   1       1   25
2  2 0 1 0 0   1   0       1   52
6  6 0 0 1 0   0   1       1    5
4  4 1 0 0 1   1   1       1   75
5  5 1 1 0 0   1   0       1   45
3  3 0 0 0 1   0   1       1   11
7  7 0 1 1 0   1   1       1   34
perms <- permute::allPerms(1:7)
mat <- as.matrix(df[,2:8])
i <- 1
while (!all(diag(mat[perms[i,],])  == rep(1,7))) {
  i = i+1
}

df[perms[i,],]

#  ID A B C D A_B C_D A_B_C_D Cost
1  1 1 0 0 1   1   1       1   25
2  2 0 1 0 0   1   0       1   52
6  6 0 0 1 0   0   1       1    5
3  3 0 0 0 1   0   1       1   11
4  4 1 0 0 1   1   1       1   75
7  7 0 1 1 0   1   1       1   34
5  5 1 1 0 0   1   0       1   45
test <- function(df){
  z <- apply(permute::allPerms(1:7), 1, function(x){
    mat <- as.matrix(df[,2:8])
    if(all(diag(mat[x,]) == rep(1,7))){
      return(df[x,])
    }
  })
  z <- Filter(Negate(is.null), z)
  return(z)
}

test2 <- function(df){
  perms <- permute::allPerms(1:7)
  mat <- as.matrix(df[,2:8])
  i <- 1
  while (!all(diag(mat[perms[i,],])  == rep(1,7))) {
    i = i+1
  }
  df[perms[i,],]
}
microbenchmark::microbenchmark(b <- test(df), 
                           c <- test2(df), times = 10L)

    Unit: milliseconds
           expr       min        lq      mean   median        uq       max neval cld
  b <- test(df) 392.68257 396.81450 412.41600 401.0613 408.15582 509.77693    10   b
 c <- test2(df)  46.11754  46.92276  47.80778  47.3977  48.82543  50.05795    10  a