You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同母仔猪栏位体重均衡分配的data.table最优算法问询

优化同母猪仔猪的栏位分配:更高效的均衡算法

你当前的启发式思路方向是对的,但确实容易陷入局部最优或者无效循环(比如你代码里的switch变量用来避免重复交换,但可能错过更好的调整机会)。下面我给你两种更可靠的方案,分别适合不同规模的数据场景。

一、改进的启发式迭代算法(适合大规模数据)

这个思路核心是每次针对性交换最能缩小均值差距的仔猪对,同时严格遵守同sowid的约束:

算法步骤

  • 计算当前各栏的平均体重,找到均值最高的栏(high_pen)和最低的栏(low_pen)
  • 在high_pen中筛选出sowid同时存在于low_pen的仔猪,取其中体重最大的个体(移走它能最大程度降低高栏均值)
  • 在low_pen中找到对应sowid的仔猪,取其中体重最小的个体(移来它能最大程度升高低栏均值)
  • 交换这两个仔猪的栏位,重复上述步骤直到均值极差≤0.1,或者没有符合条件的可交换仔猪

代码实现

library(data.table)

test <- data.table(
  sowid=c(12,23,25,45,65,12,58,85,96,85,45,23),
  pen=c(1,1,1,1,2,2,2,2,3,3,3,3),
  pigletid=c(1,2,3,4,5,6,7,8,9,10,11,12),
  weight=c(6.5,5.9,6.2,5.8,7.5,7.2,7.8,6.9,9.5,10.2,9.8,6.4)
)

cutoff <- 0.1
max_iter <- 100  # 防止无限循环
iter <- 0

while(iter < max_iter) {
  # 计算各栏均值
  pen_means <- test[, .(mean_weight = mean(weight)), by = pen]
  pen_means <- pen_means[order(mean_weight)]
  
  current_range <- pen_means$mean_weight[.N] - pen_means$mean_weight[1]
  if(current_range <= cutoff) break
  
  # 确定最高/最低均值的栏
  low_pen <- pen_means$pen[1]
  high_pen <- pen_means$pen[.N]
  
  # 筛选高栏中sowid存在于低栏的仔猪,取体重最大的
  high_piglets <- test[pen == high_pen]
  valid_sowids_high <- intersect(high_piglets$sowid, test[pen == low_pen]$sowid)
  if(length(valid_sowids_high) == 0) break  # 无交换可能
  
  candidate_high <- high_piglets[sowid %in% valid_sowids_high][order(-weight)][1]
  
  # 筛选低栏中对应sowid的仔猪,取体重最小的
  candidate_low <- test[pen == low_pen & sowid == candidate_high$sowid][order(weight)][1]
  
  # 交换栏位
  test[pigletid == candidate_high$pigletid, pen := low_pen]
  test[pigletid == candidate_low$pigletid, pen := high_pen]
  
  iter <- iter + 1
}

# 输出结果
test[order(pen)]

运行后你会发现,这个算法能更快收敛到符合要求的均值差距,而且不会陷入无效循环。

二、线性规划求最优解(适合小规模数据)

如果你的数据集不大(比如像示例这样的几十行),可以用线性规划直接求解全局最优解,确保均值差距尽可能小。这里用lpSolve包实现:

代码实现

library(data.table)
library(lpSolve)

test <- data.table(
  sowid=c(12,23,25,45,65,12,58,85,96,85,45,23),
  pen=c(1,1,1,1,2,2,2,2,3,3,3,3),
  pigletid=c(1,2,3,4,5,6,7,8,9,10,11,12),
  weight=c(6.5,5.9,6.2,5.8,7.5,7.2,7.8,6.9,9.5,10.2,9.8,6.4)
)

n_pigs <- nrow(test)
n_pens <- length(unique(test$pen))

# 目标函数:最小化各栏均值的极差
obj <- rep(0, n_pigs*n_pens + 2)
obj[n_pigs*n_pens + 1] <- 1
obj[n_pigs*n_pens + 2] <- -1

constraints <- list()
rhs <- list()
dir <- list()

# 约束1:每个仔猪只能在一个栏
for(i in 1:n_pigs) {
  row <- rep(0, n_pigs*n_pens + 2)
  row[(i-1)*n_pens + 1 : i*n_pens] <- 1
  constraints[[length(constraints)+1]] <- row
  rhs[[length(rhs)+1]] <- 1
  dir[[length(dir)+1]] <- "="
}

# 约束2:关联各栏均值与最大/最小均值
pigs_per_pen <- n_pigs / n_pens
for(j in 1:n_pens) {
  # 最大均值 >= 栏j的均值
  row <- rep(0, n_pigs*n_pens + 2)
  row[n_pigs*n_pens + 1] <- -pigs_per_pen
  row[(1:n_pigs)*n_pens - (n_pens - j)] <- test$weight
  constraints[[length(constraints)+1]] <- row
  rhs[[length(rhs)+1]] <- 0
  dir[[length(dir)+1]] <- "<="
  
  # 最小均值 <= 栏j的均值
  row <- rep(0, n_pigs*n_pens + 2)
  row[n_pigs*n_pens + 2] <- pigs_per_pen
  row[(1:n_pigs)*n_pens - (n_pens - j)] <- -test$weight
  constraints[[length(constraints)+1]] <- row
  rhs[[length(rhs)+1]] <- 0
  dir[[length(dir)+1]] <- "<="
}

# 约束3:仔猪只能分配到初始时同sowid所在的栏
for(i in 1:n_pigs) {
  allowed_pens <- unique(test[sowid == test$sowid[i]]$pen)
  for(j in 1:n_pens) {
    if(!j %in% allowed_pens) {
      row <- rep(0, n_pigs*n_pens + 2)
      row[(i-1)*n_pens + j] <- 1
      constraints[[length(constraints)+1]] <- row
      rhs[[length(rhs)+1]] <- 0
      dir[[length(dir)+1]] <- "="
    }
  }
}

# 求解线性规划
lp_result <- lp(
  direction = "min",
  objective.in = obj,
  const.mat = do.call(rbind, constraints),
  const.dir = unlist(dir),
  const.rhs = unlist(rhs),
  all.bin = c(rep(TRUE, n_pigs*n_pens), rep(FALSE, 2))
)

# 更新栏位分配
assignments <- matrix(lp_result$solution[1:(n_pigs*n_pens)], nrow = n_pigs, ncol = n_pens)
test$pen <- apply(assignments, 1, function(x) which(x == 1))

# 输出结果
test[order(pen)]

这个方法能找到满足约束的全局最优解,确保均值差距最小。

两种方案对比

  • 启发式算法:速度快,适合大规模数据集(比如上千条仔猪),能快速收敛到接近最优的解
  • 线性规划:能找到精确最优解,但计算量随数据规模增长较快,适合小规模数据集

内容的提问来源于stack exchange,提问作者DataZhukov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:32:59