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

如何在R的pso/hydroPSO包目标函数中调用迭代等计数参数?

我完全懂这种文档摸不着头脑的感觉!在PSO优化过程中要在目标函数里拿到迭代、评估和重启次数,确实需要点技巧,毕竟pso和hydroPSO的实现逻辑不太一样。下面给你分情况讲清楚,附完整示例代码:

一、使用pso包的实现方法

pso包本身没有直接把这些计数参数传递给目标函数的机制,我们可以通过自定义环境+追踪函数的方式来实现:

步骤1:创建存储计数的环境

先建一个独立环境来存迭代次数、函数评估次数和重启次数,避免污染全局变量:

library(pso)

# 创建专属环境存储计数
pso_metrics <- new.env()
pso_metrics$current_iter <- 0
pso_metrics$fn_eval_count <- 0
pso_metrics$restart_count <- 0

步骤2:定义目标函数

在目标函数里自增函数评估次数,并直接读取环境里的迭代和重启次数:

my_pso_obj <- function(x) {
  # 每调用一次目标函数,就加一次评估计数
  pso_metrics$fn_eval_count <- pso_metrics$fn_eval_count + 1
  
  # 读取当前的迭代、重启次数
  curr_iter <- pso_metrics$current_iter
  curr_restart <- pso_metrics$restart_count
  
  # 可选:打印查看参数(方便调试)
  cat(sprintf("[重启%s] 迭代%s | 已评估%s次 | 当前解:%.2f, %.2f\n",
              curr_restart, curr_iter, pso_metrics$fn_eval_count, x[1], x[2]))
  
  # 这里替换成你的目标函数计算逻辑,比如用Rosenbrock测试函数
  return(sum(100*(x[-1]-x[-length(x)]^2)^2 + (1-x[-length(x)])^2))
}

步骤3:定义追踪函数更新迭代和重启次数

pso的psoptim允许通过traceFun在每次迭代时执行自定义逻辑,我们用它来更新迭代次数,同时判断重启事件:

my_trace_fun <- function(iter, ...) {
  # 如果当前迭代回到1,且之前已有迭代记录,说明触发了重启
  if (iter == 1 && pso_metrics$current_iter > 0) {
    pso_metrics$restart_count <- pso_metrics$restart_count + 1
  }
  # 更新当前迭代次数
  pso_metrics$current_iter <- iter
}

步骤4:运行PSO优化

记得在control里开启trace=1(否则traceFun不会生效),并设置重启参数测试:

# 先重置计数
pso_metrics$current_iter <- 0
pso_metrics$fn_eval_count <- 0
pso_metrics$restart_count <- 0

# 启动优化
pso_result <- psoptim(
  par = c(0, 0),          # 初始解
  fn = my_pso_obj,        # 自定义目标函数
  lower = c(-5, -5),      # 参数下界
  upper = c(5, 5),        # 参数上界
  control = list(
    trace = 1,            # 必须开启才能触发traceFun
    traceFun = my_trace_fun,
    restart.max = 2,      # 最大重启次数
    restart.tol = 1e-6    # 重启的误差容忍度
  )
)

如果不想用全局环境,也可以用闭包封装计数和函数,更符合编程规范:

# 用闭包封装所有逻辑,避免全局变量污染
create_pso_funs <- function() {
  counts <- list(iter=0, fn_eval=0, restart=0)
  
  # 目标函数
  obj_fun <- function(x) {
    counts$fn_eval <- counts$fn_eval + 1
    cat(sprintf("[重启%s] 迭代%s | 已评估%s次\n", counts$restart, counts$iter, counts$fn_eval))
    return(sum(100*(x[-1]-x[-length(x)]^2)^2 + (1-x[-length(x)])^2))
  }
  
  # 追踪函数
  trace_fun <- function(iter, ...) {
    if (iter == 1 && counts$iter > 0) counts$restart <- counts$restart + 1
    counts$iter <- iter
  }
  
  return(list(obj=obj_fun, trace=trace_fun))
}

# 使用闭包
pso_funs <- create_pso_funs()
pso_result <- psoptim(
  par=c(0,0), fn=pso_funs$obj, lower=c(-5,-5), upper=c(5,5),
  control=list(trace=1, traceFun=pso_funs$trace, restart.max=2)
)
二、使用hydroPSO包的实现方法

hydroPSO在设计上更贴心,它会自动识别目标函数中的特定参数名,并直接传递对应的值,不需要额外的环境或追踪函数!

直接定义带参数的目标函数

只要在目标函数里加上iter(当前迭代)、nfe(函数评估次数)、restart(重启次数)这几个参数,hydroPSO就会自动把值传进来:

library(hydroPSO)

my_hydro_obj <- function(x, iter, nfe, restart) {
  # 直接用这三个参数,不需要额外处理
  cat(sprintf("[重启%s] 迭代%s | 已评估%s次 | 当前解:%.2f, %.2f\n",
              restart, iter, nfe, x[1], x[2]))
  
  # 替换成你的目标函数逻辑
  return(sum(100*(x[-1]-x[-length(x)]^2)^2 + (1-x[-length(x)])^2))
}

运行hydroPSO优化

直接调用hydroPSO,设置好参数范围和重启配置即可:

hydro_result <- hydroPSO(
  fn = my_hydro_obj,
  lower = c(-5, -5),
  upper = c(5, 5),
  init = matrix(c(0,0), ncol=2),  # 初始种群
  control = list(
    max.restarts = 2,  # 最大重启次数
    trace = 1          # 可选:开启控制台追踪
  )
)

注意事项

  • hydroPSO会根据参数名匹配传递值,所以参数名必须严格是iter、nfe、restart,顺序可以放在x之后任意位置。
  • 如果不需要某个参数,直接从目标函数里去掉就行,不影响其他参数的传递。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:25:39