随机将值分配到满足多个标准的不同大小组的数据帧/矩阵中

Chr*_*ris 6 r

这是之前提出的问题的后续问题,但增加了一层额外的复杂性,因此是一个新问题.

我有两组(下面的例子中有39380).我需要做的是将889人分配到由2至7人组成的39组中,以及由2至6人组成的380组.

但是,对某些组中的人员总数有限制.在下面的示例中,每行允许的最大值在X6列中.

使用以下示例.如果在第2行中,在第X2列分配了6个人,在第X4列分配了120个人,那么总人数将是18(6*3)+240(120*2)= 258,所以这样就可以了.不满324岁.

因此,对于每一行,我所追求的是X1*X2 + X3*X4(使列X5)的值小于或等于X6,其中X2的总和为39,X4的总和为380和总和的X5是889.理想的情况下任何的解决办法是尽可能随机的(所以如果重复你会得到如果可能不同的解决方案),当值是889,39和380不同,将工作和一个.

谢谢!

DF <- data.frame(matrix(0, nrow = 7, ncol = 6))
DF[,1] <- c(2:7,"Sum")
DF[7,2] <- 39
DF[2:6,3] <- 2:6
DF[7,4] <- 380
DF[7,5] <- 889
DF[1:6,6] <- c(359, 324, 134, 31, 5, 2)
DF[1,3:4] <- NA
DF[7,3] <- NA
DF[7,6] <- NA
Run Code Online (Sandbox Code Playgroud)

编辑

我的问题的措辞可能不是最清楚的.以下是我目前使用的代码示例以及它不符合我上面设置的条件

homeType=rep(c("a", "b"), times=c(39, 380))
H <- vector(mode="list", length(homeType))
for(i in seq(H)){
  H[[i]]$type <- homeType[i]
  H[[i]]$n <- 0
}

# Place people in houses up to max number of people
npeople <- 889
for(i in seq(npeople)){
  placed_in_house <- FALSE
  while(!placed_in_house){
    house_num <- sample(length(H), 1)
    if(H[[house_num]]$type == "a"){
      if(H[[house_num]]$n < 7){
        H[[house_num]]$n <- H[[house_num]]$n + 1
        placed_in_house <- TRUE
      }
    }
    if(H[[house_num]]$type == "b"){
      if(H[[house_num]]$n < 6){
        H[[house_num]]$n <- H[[house_num]]$n + 1
        placed_in_house <- TRUE
      }
    }
  }
}

# move people around to get up to min number of people
for(i in seq(H)){
  while(H[[i]]$n < 2){
    knock_on_door <- sample(length(H), 1)
    if( H[[knock_on_door]]$n > 2){
      H[[i]]$n <- H[[i]]$n + 1 # house i takes 1 person
      H[[knock_on_door]]$n <- H[[knock_on_door]]$n - 1 # house knock_on_door loses 1 person
    }
  }
}

Ha <- H[which(lapply(H, function(x){x$type}) == "a")]
Hb <- H[which(lapply(H, function(x){x$type}) == "b")]

Ha_T <- data.frame(t(table(data.frame(matrix(unlist(Ha), nrow=length(Ha), byrow=T)))))
Hb_T <- data.frame(t(table(data.frame(matrix(unlist(Hb), nrow=length(Hb), byrow=T)))))

DF_1 <- data.frame(matrix(0, nrow = 7, ncol = 6))
DF_1[,1] <- c(2:7,"Sum")
DF_1[7,2] <- 39
DF_1[2:6,3] <- 2:6
DF_1[7,4] <- 380
DF_1[7,5] <- 889
DF_1[1:6,6] <- c(359, 324, 134, 31, 5, 2)
for(i in 1:nrow(Ha_T)){DF_1[as.numeric(as.character(Ha_T[i,1]))-1,2] <- Ha_T[i,3]}
for(i in 1:nrow(Hb_T)){DF_1[as.numeric(as.character(Hb_T[i,1])),4] <- Hb_T[i,3]}
DF_1$X5[1:6] <- (as.numeric(as.character(DF_1$X1[1:6]))*DF_1$X2[1:6])+(as.numeric(as.character(DF_1$X3[1:6]))*DF_1$X4[1:6])
DF_1$X7 <- DF_1$X2+DF_1$X4
DF_1[1,3:4] <- NA
DF_1[7,3] <- NA
DF_1[7,6] <- NA
Run Code Online (Sandbox Code Playgroud)

使用此示例,问题是DF_1中的第2行.列X7(X2 + X4)中的值大于列X6中显示的允许数量.我需要的是一个解决方案,其中X7中的值小于或等于X6中的值,但列X2,X4和X5(X1*X2 + X3*X4)的总和分别等于39,380和889(尽管这些数字根据使用的数据而变化).

dww*_*dww 1

问题中问题的原始描述是不可能满足的,因为没有值可以满足所有这些约束。

“所以我对每一行的要求是 X1*X2 + X3*X4(构成 X5 列)的值小于或等于 X6,其中 X2 的总和为 39,X4 的总和为 380,总计X5 之和为 889。”

然而,在评论中重述问题之后,问题的修改描述可以解决如下。

更新:基于评论中问题澄清的解决方案

根据评论中的澄清

“我实际上并没有完全填写房屋数量。我只是将孩子的数量分配到房屋中。这就是为什么'a'是2到7而'b'是2到6,因为'a'家庭还将包括1 个成人和“b”家庭 2. 对于给定区域,我知道有多少个 2 至 8 人家庭 (419),以及有多少个 2、3、4、5、6、7 或 8 人家庭 (359,324,134, 31,5,2)。我还知道有 1 (39) 或 2 (380) 名成人的家庭总数,以及有多少儿童(在我的示例中为 889)。”

根据这些更新的信息,我们可以执行以下操作,其中我们循环 1)根据标准计算每种类型还可以分配多少房屋,2)随机选择一种在不违反规定的情况下仍可以分配的房屋类型规则 3) 之一并重复,直到所有 889 名儿童都在家里。请注意,我在这里使用更具描述性的列名称,以便更容易遵循逻辑:

DT <- data.table(HS1 = 2:7, # type 1 house size
                 NH1 = 0,   # number of type 1 houses with children
                 HS2 = 1:6, # type 2 house size
                 NH2 = 0,   # number of type 2 houses with children
                 C = 0,     # number of children in houses
                 MaxNH = c(359, 324, 134, 31, 5, 2)) # maximum number of type1+type 2 houses
NR = DT[,.N]
set.seed(1234)
repeat {
  while (DT[, sum(C) < 889]) {
    DT[, MaxH1 := (MaxNH - NH1 - NH2)]
    DT[, MaxH2 := (MaxNH - NH1 - NH2)]
    DT[1,MaxH2 := 0 ]
    DT[MaxH1 > 39 - sum(NH1), MaxH1 := 39 - sum(NH1)]
    DT[MaxH2 > 380- sum(NH2), MaxH2 := 380- sum(NH2)]
    if (DT[, sum(NH1)] >= 39)  DT[, MaxH1 := 0]
    if (DT[, sum(NH2)] >= 380) DT[, MaxH1 := 0]

    if (DT[, all(MaxH1==0) & all(MaxH2==0)]) { # check if it is not possible to assign anyone else to a group
      print("No solution found. Check constraints or try again")
      break
    }
    # If you wish to preferentially fill a particular type of house, then change the probability weights in the next line accordingly
    newgroup = sample(2*NR, 1, prob = DT[, c(MaxH1, MaxH2)])
    if (newgroup > NR) DT[rep(1:NR, 2)[newgroup], NH2 := NH2+1] else DT[rep(1:NR, 2)[newgroup], NH1 := NH1+1]

    DT[, C := HS1*NH1 + HS2*NH2]
  }
  if (DT[, sum(C)==889]) break
}

DT[,1:6, with=F]
#   HS1 NH1 HS2 NH2   C MaxNH 
#1:   2   7   1   0  14   359 
#2:   3   7   2 218 457   324 
#3:   4  14   3  76 284   134  
#4:   5   9   4  14 101    31  
#5:   6   2   5   3  27     5 
#6:   7   0   6   1   6     2 

colSums(DT[, .(NH1, NH2, C)])
# NH1 NH2   C 
#  39 312 889  
Run Code Online (Sandbox Code Playgroud)