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

在R中从100K行data.table选1K行优化加权和的算法建议

针对大规模数据集子集优化的解决方案(R语言)

首先,我先梳理下你的核心需求:从100万行的数据集中选取1000行子集,最大化一个包含**全局统计量(max(x1)、max(x4))和总和统计量(sum(x2))**的代价函数,并且结果要优于简单排序或随机选择。

先简化你的代价函数(方便分析,x3项在原函数中被抵消了,可能是笔误?如果后续需要加入x3的影响,我们可以再调整):

# 原代价函数等价简化
Simplified_Cost <- function(x1, x2, x4) {
  0.2 * max(x1) + 0.1 * sum(x2) - 0.1 * max(x4)
}

这个目标函数的特点是:不需要每行独立打分求和,而是依赖子集的全局属性,所以简单排序选前N行的思路存在局限性——排序只考虑了单行的权重,没有兼顾全局max项的特性(比如max(x1)只需要保留一个最大值,剩下的999行可以优先选x2大且x4小的)。

下面给出几种实用的算法和实现方案,效果都会优于你当前的方法:


一、利用目标函数特性的特殊优化(最快且效果好)

因为你的目标函数结构明确,我们可以针对性简化问题:

  1. 固定max(x1)的行:因为max(x1)对结果有正向贡献,直接保留x1最大的那一行即可,不需要在子集里保留多个高x1的行;
  2. 筛选剩余行:剩下的999行,优先选x2大且x4小的行(因为sum(x2)正向贡献,max(x4)负向贡献)。

实现代码:

# 修正合成数据的x2生成bug(原代码只生成10万行,这里改成100万行)
set.seed(123)
total <- data.frame(
  id = 1:1000000, 
  x1 = runif(1000000,0,1), 
  x2 = 60*runif(1000000,0,1),  # 修正此处
  x3 = runif(1000000,0,1), 
  x4 = runif(1000000,0,1), 
  Last_interaction = sample(1:35, 1000000, replace= T)
)
total$x3 <- -total$x2 * total$x3 * runif(1000000,0.7,1) # 修正此处

# 特殊优化方案
# 1. 保留x1最大的行
max_x1_row <- total[which.max(total$x1),]
# 2. 过滤掉x4排名前10%的行(避免max(x4)拉低分数),然后选x2最大的999行
filtered_remaining <- total[-which.max(total$x1),]
filtered_remaining <- filtered_remaining[filtered_remaining$x4 < quantile(filtered_remaining$x4, 0.9),]
result_special <- rbind(max_x1_row, filtered_remaining[order(-filtered_remaining$x2),][1:999,])

# 计算代价
Simplified_Cost(result_special$x1, result_special$x2, result_special$x4)

这种方法利用了目标函数的结构,计算速度极快,结果大概率会超过排序选优的效果。


二、启发式算法(通用且效果稳定)

如果你的目标函数后续可能调整,或者需要更通用的方案,推荐以下两种启发式方法:

1. 贪心算法+候选池优化

直接在100万行上做贪心会很慢,所以先构建一个候选池(包含所有对目标函数关键的行),再在候选池内做贪心:

# 构建候选池:取x1前100行、x2前10000行、x4前10000行(去重)
candidate_pool <- unique(rbind(
  total[order(-x1),][1:100,],
  total[order(-x2),][1:10000,],
  total[order(x4),][1:10000,]
))
n_candidate <- nrow(candidate_pool)

# 贪心添加法:从空集开始,每次加入能最大提升代价的行
current_subset <- c()
current_cost <- -Inf
for (i in 1:1000) {
  best_gain <- -Inf
  best_row <- NA
  # 遍历候选池中未选中的行
  for (j in setdiff(1:n_candidate, current_subset)) {
    temp_subset <- c(current_subset, j)
    temp_cost <- Simplified_Cost(
      candidate_pool$x1[temp_subset],
      candidate_pool$x2[temp_subset],
      candidate_pool$x4[temp_subset]
    )
    gain <- temp_cost - current_cost
    if (gain > best_gain) {
      best_gain <- gain
      best_row <- j
    }
  }
  current_subset <- c(current_subset, best_row)
  current_cost <- current_cost + best_gain
  if (i %% 100 == 0) cat("已选", i, "行,当前代价:", current_cost, "\n")
}
result_greedy <- candidate_pool[current_subset,]

2. 局部搜索优化(在贪心结果上进一步提升)

在贪心结果的基础上,通过随机替换行来寻找更优解:

# 基于贪心结果做局部搜索
current_subset <- current_subset
current_cost <- Simplified_Cost(
  candidate_pool$x1[current_subset],
  candidate_pool$x2[current_subset],
  candidate_pool$x4[current_subset]
)
n_iter <- 10000 # 迭代次数
for (i in 1:n_iter) {
  # 随机替换子集内的一行和候选池内未选中的一行
  idx_remove <- sample(current_subset, 1)
  idx_add <- sample(setdiff(1:n_candidate, current_subset), 1)
  temp_subset <- replace(current_subset, which(current_subset == idx_remove), idx_add)
  temp_cost <- Simplified_Cost(
    candidate_pool$x1[temp_subset],
    candidate_pool$x2[temp_subset],
    candidate_pool$x4[temp_subset]
  )
  if (temp_cost > current_cost) {
    current_subset <- temp_subset
    current_cost <- temp_cost
    cat("迭代", i, ",代价提升至:", current_cost, "\n")
  }
}
result_local <- candidate_pool[current_subset,]

三、使用专门的优化库(全局搜索)

如果需要更强大的全局优化能力,可以用R的遗传算法库:

GA包(遗传算法)

遗传算法通过模拟自然选择来探索最优子集,适合离散的组合优化问题:

library(GA)

# 定义适应度函数(约束选中1000行)
fitness <- function(ind) {
  selected <- which(ind == 1)
  if (length(selected) != 1000) return(-Inf)
  Simplified_Cost(
    candidate_pool$x1[selected],
    candidate_pool$x2[selected],
    candidate_pool$x4[selected]
  )
}

# 运行遗传算法
ga_result <- ga(
  type = "binary",
  fitness = fitness,
  nBits = n_candidate,
  popSize = 50,
  maxiter = 100,
  run = 20, # 连续20代无提升则停止
  pmutation = 0.1,
  crossover = gabin_uCrossover
)

# 提取最优解
best_ind <- ga_result@solution[1,]
result_ga <- candidate_pool[which(best_ind == 1),]

四、结果对比

你可以把所有方法的结果和原方法对比:

# 原方法结果
cost_1 <- Simplified_Cost(result_1$x1, result_1$x2, result_1$x4)
cost_2 <- Simplified_Cost(result_2$x1, result_2$x2, result_2$x4)

# 新方法结果
cost_special <- Simplified_Cost(result_special$x1, result_special$x2, result_special$x4)
cost_greedy <- Simplified_Cost(result_greedy$x1, result_greedy$x2, result_greedy$x4)
cost_local <- Simplified_Cost(result_local$x1, result_local$x2, result_local$x4)
cost_ga <- Simplified_Cost(result_ga$x1, result_ga$x2, result_ga$x4)

# 打印对比
cat("排序选优:", round(cost_1, 2), "\n")
cat("随机选择:", round(cost_2, 2), "\n")
cat("特殊优化:", round(cost_special, 2), "\n")
cat("贪心算法:", round(cost_greedy, 2), "\n")
cat("局部搜索:", round(cost_local, 2), "\n")
cat("遗传算法:", round(cost_ga, 2), "\n")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:15:06