English Русский Español Deutsch 日本語 Português
preview
种群优化算法:树苗播种和成长(SSG)算法

种群优化算法:树苗播种和成长(SSG)算法

MetaTrader 5示例 | 14 八月 2023, 09:36
865 0
Andrey Dik
Andrey Dik

内容:

1. 概述
2. 算法
3. 测试结果


1. 概述

自然界中所有生物都受某些规律的约束。 这有助于它们在不断变化的环境条件下生存。 植物对环境的适应性有多种选择。 其中一些能够忍受季节变化,另一些可以适应缺乏水分、高温或低温、以及没有传粉媒介。 植物中最稳定的生物之一是树木,其中一些能够存活超过 50 万年,形成群落。

大自然是取之不尽用之不竭的灵感领域,其是开发许多有效计算方法和发明的思想源泉。 事实上,进化计算是以计算机模拟的进化投影。 有许多优化方法受到自然界中发生的过程的启发,例如进化计算、人工免疫学、种群方法、等等。 SSG 基本上被定义为迭代生成和组合过程,与称为幼苗的潜在解花园配合工作。 树苗播种和生长(SSG)算法是由 A. Karci 与合著者在 2002 年提出的。 该算法的灵感来自成长树木的演变,并模拟了树木的生长和开枝散叶。


2. 算法

该算法是少数几个没有作者明确讲述的算法之一(仅提供一般规定和思路)。 由作者提出的算法操作符,算法也没有现成的程序指令实现。 没有关于子树和父树、及其交互的明确说明。 对于操作符的执行顺序没有要求,任何用户都可以更改其顺序,从而能获得更好的幼苗。

从广义上讲,SSG 并非是一种优化算法,它是一组通用规则,旨在补充其它算法,从而提高优化品质。 换言之,SSG 是任何种群进化算法的附加组件,如此我就有了想象的空间,并有机会尝试优化算法的特定实现。 我在编写以前的算法时应用了自己的一些想法和经验,并使用它们与 SSG 配合工作。 实验结果如下,供读者判断。

为了开始理解算法,我们需要将这棵树想象为优化代理者。 一棵树是优化问题的解,其中每个枝杈都是问题的优化参数。 图例 1 提供了子树和父树的抽象和艺术描绘图。 树干是一组要优化的参数。 每个枝杈都是一个单独的优化参数,其中枝杈的长度受相应参数的允许值范围的限制。 枝杈的方向无关紧要,仅在图中显示来高亮显示它们的差异。

树

图例 1. 子树和父树。 虚线表示被父枝杈替换的子枝杈

因此,树枝是搜索空间中树的坐标。

SSG 算法由生成新解的变异操作符组成 — 公共解池子的候选者。 主要的变异操作符是交叉枝杈疫苗接种。 种植幼苗应在各个方向(西、东、北、南)等距离进行,这是该方法的初始阶段。 当坐标(优化参数)远大于三个时,“均匀”种植是在搜索空间上幼苗的简单随机分布。 然后幼苗成长、杂交、开枝散叶、并进行疫苗接种过程。

我们来研究一下 SSG 算法的步骤和操作符:

1) 种植幼苗。

搜索空间可以被认为是一个幼苗花园,因此所有幼苗必须均匀分布在整个花园中。 当栽植幼苗时,农民只简单地将它们撒到彼此相等的距离,如此幼苗生长得更快,且不会相互干扰。 为了通过模拟幼苗的栽培来解决问题,最初要生成的任意解必须均匀分布在有效的搜索空间当中。

当有两个或三个坐标时,幼苗均匀分布没有问题,但是当坐标远远超过三个坐标时,使用随机分布更容易。 在实践中,坐标数量少,无需注意幼苗的均匀分布,因为任务本身不是一个大问题,且已知能获得高精度解。 因此,无论算法中的坐标数量如何,我们在花园中里都会随机分布幼苗。

2)幼苗生长(树木),三个操作符依次执行。

2.1) 交叉。

“交叉”操作符的目的是通过在现有幼苗之间交换信息来创建新的幼苗。 交叉本质上是将枝杈的副本从父树移植到子树(图例 1)。 对于每对幼苗,采用不同的交叉系数,即交叉概率。 杂交的概率取决于一对幼苗之间的距离,距离越大,杂交的概率越低。 交叉操作符是提供组合机制的算法中非常重要的方法。 在代理者之间组合信息可以显著提高优化算法的整体品质。

2.2)开枝散叶。

操作符对开枝散叶的成长进行建模。 成长即可为正(伸长)亦或为负(干枯)。 “为了在幼苗的任何地方长出树枝,附近都不会有以前发芽的树枝”。 这是算法作者对操作符的大致描述。 事实上,这个过程比初看更简单、更清晰,并且是对子树现有枝杈的修改(未指定具体的修改方法)。

独立枝杈的修改可能性越大,当前迭代与上次修改枝杈的迭代之间经过的迭代次数越多。 我的实验表明这个操作符效率低下。 此外,没有直接迹象表明使用了修改方法,我在这件事上是主动的,根据利维(Levy)飞行分配法则应用了枝杈长度的变化。 修改将采为算法外部参数指定的概率和强度执行。

2.3) 疫苗。

在幼苗相似的情况下,疫苗接种过程在两个不同的幼苗之间进行。 幼苗的相似性影响疫苗接种过程的成功,并与加权距离的算术平均值成正比。 该操作符类似于交叉操作符,由枝杈交换组成,为算法提供了一种在代理者之间组合信息的额外方法。 该操作将在文章中高亮显示,但是该操作符在源代码中被注释掉,且显示的测试结果它并无参与,因为疫苗接种会令结果恶化。

3) 计算树木的适应性。

4) 在花园里种植新苗。

在交叉、枝杈和疫苗接种操作符的帮助下获得的幼苗是临时解决方案(女儿花园)。 在这个阶段,有必要选择 n 个最好的幼苗(算法的外部参数),并将它们放置在花园中,替换花园中 n 棵最差的树。 应该注意的是,无论如何都会替换幼苗,即使它们比花园中最糟糕的树更糟糕。
这是查看生长树算法代码的好时机,带领我们稳步接近本项研究令人兴奋的高潮 — 测试结果的审查。

故此,将每棵树表示为花园结构很方便,这将作为创建花卉花园的基础。 在这个算法中,没有什么比“树”实体更简单的了,它只需要两个组件:带有 [] 的坐标,和适应度值 f。

//——————————————————————————————————————————————————————————————————————————————
struct S_Garden
{
  double c []; //coordinates
  double f;    //fitness
};
//——————————————————————————————————————————————————————————————————————————————

SG 算法的 C_AO_SSG 类没什么特别的。 这里的一切对于我们都非常熟悉,其来自前面研究过的算法。 在类中,我们将声明在父花园和子花园上运行的成员和方法。 临时花园旨在令排序方法发挥作用,因为我们需要对子花园和父花园进行排序。 我们来声明一个包含整个解的最佳坐标,和最佳适应度值的数组,以及用于存储算法外部参数的常量变量。

//——————————————————————————————————————————————————————————————————————————————
class C_AO_SSG
{
  //============================================================================
  public: double rangeMax  []; //maximum search range
  public: double rangeMin  []; //manimum search range
  public: double rangeStep []; //step search
  public: S_Garden pGarden []; //parent's garden
  public: S_Garden cGarden []; //child's garden
  public: S_Garden gardenT []; //temp garden
  public: double cB        []; //best coordinates
  public: double fB;           //fitness of the best coordinates

  public: void Init (const int    coordinatesP,          //Number of coordinates
                     const int    numberTreesP,          //Number of trees
                     const double seedlingsReplacementP, //Seedlings replacement
                     const double probabMatingOperatorP, //Probability mating operator
                     const double probabBranchOperatorP, //Probability branching operator
                     const double powerBranchOperatorP); //Power branching operator

  public: void Sowing      (int iter);
  public: void Germination ();


  //============================================================================
  private: void   Sorting        (S_Garden &garden []);
  private: double SeInDiSp       (double In, double InMin, double InMax, double Step);
  private: double RNDfromCI      (double Min, double Max);
  private: double Scale          (double In, double InMIN, double InMAX, double OutMIN, double OutMAX,  bool Revers);

  private: double vec [];               //Vector
  private: int    ind [];
  private: double val [];
  private: double r;

  private: bool   sowing;               //Sowing
  private: int    coordinates;          //Coordinates number
  private: int    numberTrees;          //Number of trees
  private: int    seedlingsReplacement; //Seedlings replacement
  private: double probabMatingOperator; //Probability mating operator
  private: double probabBranchOperator; //Probability branching operator
  private: double powerBranchOperator;  //Power branching operator
};
//——————————————————————————————————————————————————————————————————————————————

在 Init() 初始化方法中,为数组分配内存,并将数值赋值给常量参数。 由于 seedlingsReplacementP 参数设置为花园大小的分数(从 0.0 到 1.0),该参数负责在父花园中种植的子幼苗数量,因此应将其转换为花园大小的整数表示形式。 我们来重置初始花园幼苗标志,并用尽可能小的双精度值初始化全局决策变量。

//——————————————————————————————————————————————————————————————————————————————
void C_AO_SSG::Init (const int    coordinatesP,          //Number of coordinates
                     const int    numberTreesP,          //Number of trees
                     const double seedlingsReplacementP, //Seedlings replacement
                     const double probabMatingOperatorP, //Probability mating operator
                     const double probabBranchOperatorP, //Probability branching operator
                     const double powerBranchOperatorP)  //Power branching operator
{
  MathSrand (GetTickCount ());
  sowing = false;
  fB     = -DBL_MAX;

  coordinates    = coordinatesP;
  numberTrees    = numberTreesP;

  if (seedlingsReplacementP >= 1.0)
  {
    seedlingsReplacement = numberTreesP;
  }
  else
  {
    if (seedlingsReplacementP <= 0.0)
    {
      seedlingsReplacement = 1;
    }
    else seedlingsReplacement = int(numberTreesP * seedlingsReplacementP);
  }

  probabMatingOperator = probabMatingOperatorP;
  probabBranchOperator = probabBranchOperatorP;
  powerBranchOperator  = powerBranchOperatorP;

  ArrayResize (rangeMax,  coordinates);
  ArrayResize (rangeMin,  coordinates);
  ArrayResize (rangeStep, coordinates);
  ArrayResize (vec,       coordinates);
  ArrayResize (cB,        coordinates);


  ArrayResize (pGarden,  numberTrees);
  ArrayResize (cGarden,  numberTrees);
  ArrayResize (gardenT,  numberTrees);
  ArrayResize (ind,      numberTrees);
  ArrayResize (val,      numberTrees);

  for (int i = 0; i < numberTrees; i++)
  {
    ArrayResize (pGarden  [i].c, coordinates);
    ArrayResize (cGarden  [i].c, coordinates);
    ArrayResize (gardenT  [i].c, coordinates);
    cGarden [i].f = -DBL_MAX;
  }
}
//——————————————————————————————————————————————————————————————————————————————

每次迭代时调用的第一个公开方法 Sowing() 是播种。 在第一次迭代中,当算法刚刚运行时,我们将随机在花园(搜索空间)周均匀分布幼苗。 在此,我们看到坐标是在优化参数的最小值和最大值之间的允许范围内随机生成的,我们检查是否自允许范围退出,然后根据优化步骤带来坐标值。

在这个阶段,幼苗的适应性最小。 我们设置 vec[] 向量。 我们需要它来缩放枝杈操作符中枝杈的增量,并计算搜索空间中最大可能的欧几里得距离 r。 在交叉操作符中,根据树对之间的距离判定概率将很有用。

//the first planting of trees-------------------------------------------------
if (!sowing)
{
  fB = -DBL_MAX;
  r = 0.0;

  for (int t = 0; t < numberTrees; t++)
  {
    for (int c = 0; c < coordinates; c++)
    {
      cGarden [t].c [c] = RNDfromCI (rangeMin [c], rangeMax [c]);
      cGarden [t].c [c] = SeInDiSp (cGarden [t].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
    }

    cGarden [t].f = -DBL_MAX;
  }

  for (int c = 0; c < coordinates; c++)
  {
    vec [c] = rangeMax [c] - rangeMin [c];
    r += vec [c] * vec [c];
  }

  r = sqrt (r);

  return;
}

接下来,在 Sowing() 方法中,在第二次和后续迭代中执行交叉、枝杈和疫苗接种操作符。 操作符在主循环中按顺序执行:

//tree growth-----------------------------------------------------------------
int child, parent;
double rnd;
double ed; //euclidean distance
double eM;
double u;
double temp;

for (int t = 0; t < numberTrees; t++)

在执行操作符时,“子”和“父”的概念非常随意。 事实上,它们只是创建新幼苗的基本信息来源。 新幼苗从子树复制所有枝杈(您可能还记得,枝杈是要优化的参数),并从父树接收新枝杈。

对于每棵新幼苗,从花园中单独选择两棵树,一棵子树和一棵亲树随机选择,花园中的所有树木的可能性相同。 换言之,所有树木都能以相同的概率参与新幼苗的创建,无论它们的健康状况如何。 因此,“子”和“父”只是父花园数组中原始两棵树的索引。

ed = 0.0;

rnd = RNDfromCI (0.0, numberTrees - 1);
child = (int)MathRound (rnd);
if (child < 0) child = 0;
if (child > numberTrees - 1) child = numberTrees - 1;

rnd = RNDfromCI (0.0, numberTrees - 1);
parent = (int)MathRound (rnd);
if (parent < 0) parent = 0;
if (parent > numberTrees - 1) parent = numberTrees - 1;

if (child == parent) parent++;
if (parent > numberTrees - 1) parent = 0;

ArrayCopy (cGarden [t].c, pGarden [child].c, 0, 0, WHOLE_ARRAY);

第一个操作符是交叉或共轭(配对)。 为了在索引为 t 的幼苗上执行交叉操作符,必须使用“子”和“父”索引计算子树和父树之间的欧几里得空间:

//mating operator-----------------------------------------------------------
for (int c = 0; c < coordinates; c++)
{
  temp = pGarden [child].c [c] - pGarden [parent].c [c];
  ed += temp * temp;
}

ed = sqrt (ed);

计算交叉概率等式里的欧几里得距离,是搜索空间中的最大可能欧几里得距离 r 的归一化:

eM = 1.0 - (ed / r);

生成 [0.0;1.0] 范围内的随机数。 如果结果数字落在计算的概率 eM 范围内,那么我们执行交叉 — 从父树复制枝杈,每个枝杈的 probabMatingOperator 概率。 如果不满足 eM 概率,则幼苗将继续执行具有子树的所有原始枝杈的下一个语句。

rnd = RNDfromCI (0.0, 1.0);

if (rnd <= eM)
{
  for (int c = 0; c < coordinates; c++)
  {
    rnd = RNDfromCI (0.0, 1.0);

    if (rnd <= probabMatingOperator) cGarden [t].c [c] = pGarden [parent].c [c];
  }
}

接下来,执行枝杈操作符。 枝杈提供了枝杈的变种 — 加长和缩短。 这是创建新长度枝杈的主操作符。 其余操作符仅执行组合角色,不创建新的唯一枝杈。 对于每个枝杈,我们在 [0.0;1.0] 范围内生成一个随机数,如果满足 probabBranchOperator 的概率,则我们依据此处研究的 利维(Levy)飞行分布定律,通过更改枝杈的长度来执行枝杈。

如您所见,并非所有幼苗的枝杈都会改变。 无论枝杈是从上一个语句中的父树复制的,还是原始子枝杈,它们都会被更改。 修改枝杈后,我们检查超出范围的值,令其与优化步骤保持一致。

//branching operator--------------------------------------------------------
for (int c = 0; c < coordinates; c++)
{
  rnd = RNDfromCI (0.0, 1.0);

  if (rnd < probabBranchOperator)
  {
    double r1 = RNDfromCI (0.0, 1.0);
    r1 = r1 > 0.5 ? 1.0 : -1.0;
    double r2 = RNDfromCI (1.0, 20.0);

    cGarden [t].c [c] = cGarden [t].c [c] + r1 * vec [c] * powerBranchOperator * pow (r2, -2.0);
    cGarden [t].c [c] = SeInDiSp (cGarden [t].c [c], rangeMin [c], rangeMax [c], rangeStep [c]);
  }
}

第三个操作符是疫苗接种。 显然,作者将疫苗接种操作符设想为组合操作符,并且应该在子树和父树的枝杈差异超过所有分支的平均差异的情况下从父树复制枝杈。 它听起来很复杂,但是这个操作符几乎没有用处,因此这个操作符在源文件中被注释掉了。 在这种情况下,我不能冒充专家,因此我承认对该操作符有误解的可能性。

//vaccinating operator------------------------------------------------------
u = 0.0;
    
for (int c = 0; c < coordinates; c++)
{
  u += fabs (cGarden [t].c [c] - pGarden [parent].c [c]) / vec [c];
}

u /= coordinates;

for (int c = 0; c < coordinates; c++)
{
  if (fabs (cGarden [t].c [c] - pGarden [parent].c [c]) / vec [c] >= u)
  {
    cGarden [t].c [c] = pGarden [parent].c [c];
  }
}

最后的时刻来到了,一个重要但并非关键的算法操作 — 发芽。 我们执行第二个公开方法 Geneination(),该方法在每次迭代时都必须执行。

如果第一次迭代即将结束(我们肯定会依据 “sowing” 标志知道这一点),那么这意味着父花园是空的。 我们将子花园的所有幼苗种植在父花园中,只需一棵接一棵复制所有幼树即可。 之后,调用 Sorting() 方法按适应度值对父花园进行排序。 如果所有树木已排序,则索引为 0 的树将具有最佳适应度,如果它不是最好的,我们可以更新最佳全局解。

if (!sowing)
{
  for (int t = 0; t < numberTrees; t++) pGarden [t] = cGarden [t];

  Sorting (pGarden);

  if (pGarden [0].f > fB)
  {
    fB = pGarden [0].f;

    ArrayCopy (cB, pGarden [0].c, 0, 0, WHOLE_ARRAY);
  }
  
  sowing = true;
  return;
}

在代码中深入,我们只会进入算法中的第二次和后续迭代,因为 “sowing” 标志已被谨慎地设置为 “true”。 在第二次及后续的迭代中,在将幼苗转移到父花园,并替换最差的树木之前,必须对子花园进行排序。 我们检查全局解是否有所改进,然后将最好的 n 棵幼苗复制到父花园的末尾。

总之,剩下的只是对父花园进行排序。 花园社会的新成员将能够取代老一辈的树木,解决优化问题结果,就是鲜花盛开取悦我们。

//planting some part from all child trees-------------------------------------
Sorting (cGarden);

if (cGarden [0].f > fB)
{
  fB = cGarden [0].f;

  ArrayCopy (cB, cGarden [0].c, 0, 0, WHOLE_ARRAY);
}

for (int t = 0; t < seedlingsReplacement; t++) pGarden [numberTrees - seedlingsReplacement + t] = cGarden [t];

Sorting (pGarden);


3. 测试结果

SSG 测试台结果

2023.03.09 12:50:37.207    Test_AO_SSG (GBPUSD,M1)    C_AO_SSG:50;0.3;0.5;0.4;0.1
2023.03.09 12:50:37.207    Test_AO_SSG (GBPUSD,M1)    =============================
egu 2023.03.09 12:50:45.954    Test_AO_SSG (GBPUSD,M1)    Score: 0.99998
2023.03.09 12:50:59.290    Test_AO_SSG (GBPUSD,M1)    25 Rastrigin's; Func runs 10000 result: 77.3972262608643
2023.03.09 12:50:59.290    Test_AO_SSG (GBPUSD,M1)    Score: 0.95900
2023.03.09 12:52:25.368    Test_AO_SSG (GBPUSD,M1)    500 Rastrigin's; Func runs 10000 result: 52.24518909141432
2023.03.09 12:52:25.368    Test_AO_SSG (GBPUSD,M1)    Score: 0.64735
2023.03.09 12:52:25.368    Test_AO_SSG (GBPUSD,M1)    =============================
2023.03.09 12:52:31.419    Test_AO_SSG (GBPUSD,M1)    5 Forest's; Func runs 10000 result: 1.331178589711503
2023.03.09 12:52:31.419    Test_AO_SSG (GBPUSD,M1)    Score: 0.75298
2023.03.09 12:52:42.575    Test_AO_SSG (GBPUSD,M1)    25 Forest's; Func runs 10000 result: 1.019329018074209
2023.03.09 12:52:42.575    Test_AO_SSG (GBPUSD,M1)    Score: 0.57658
2023.03.09 12:53:48.922    Test_AO_SSG (GBPUSD,M1)    500 Forest's; Func runs 10000 result: 0.25410121872226443
2023.03.09 12:53:48.922    Test_AO_SSG (GBPUSD,M1)    Score: 0.14373
2023.03.09 12:53:48.922    Test_AO_SSG (GBPUSD,M1)    =============================
2023.03.09 12:53:57.201    Test_AO_SSG (GBPUSD,M1)    5 Megacity's; Func runs 10000 result: 6.4
2023.03.09 12:53:57.201    Test_AO_SSG (GBPUSD,M1)    Score: 0.53333
2023.03.09 12:54:08.004    Test_AO_SSG (GBPUSD,M1)    25 Megacity's; Func runs 10000 result: 4.504
2023.03.09 12:54:08.004    Test_AO_SSG (GBPUSD,M1)    Score: 0.37533
2023.03.09 12:56:07.061    Test_AO_SSG (GBPUSD,M1)    500 Megacity's; Func runs 10000 result: 1.2336
2023.03.09 12:56:07.061    Test_AO_SSG (GBPUSD,M1)    Score: 0.10280
2023.03.09 12:56:07.061    Test_AO_SSG (GBPUSD,M1)    =============================
2023.03.09 12:56:07.061    Test_AO_SSG (GBPUSD,M1)    All score: 5.09109

SSG 没有太多参数,尽管这是正在调整的算法结果(原始 SSG 的参数更少)。 不过,所有参数都值得特别注意。 测试中用到以下参数。 您可能还记得,在每篇文章中,我都提供了最好的算法参数,在测试中产生尽可能高的结果。

C_AO_SSG:50;0.3;0.5;0.4;0.1

input int NumberTrees_P = 50;  - 花园里的树木数量。 我没有尝试采用此参数的保留默认值(实验中的默认值)。 如果值为 100,则算法会产生更好的聚合结果,但由于减少了给定大小的花园迭代次数,则缩放能力会降低。 拥有大量树枝的花园没有时间进化。

input double SeedlingsReplacement_P = 0.3; - 将子花园的幼苗转移到亲本花园的比例。
input double ProbabMatingOperator_P = 0.5; - 交叉的概率(从父树复制枝杈),如果考虑到一对树之间的距离的概率得到满足。
input double ProbabBranchOperator_P = 0.4; - 分杈概率(枝杈的生长/收缩)。 这是一个显著影响算法性能的重要参数(通常,所有参数都很重要)。 input double PowerBranchOperator_P  = 0.1; - 枝杈强度。 这是正在优化的参数维度中的比例因子,1.0 或更高将意味着枝杈生长到花园的边界,0.0 — 没有枝杈生长,也就是说,不会出现新的枝杈大小,算法退化为简单的组合工具(这可能就是使用 SSG 的好主意, 然而,这里需要更多的研究)。

如果您关注 SSE 算法在测试函数上的动画,您会发现花园里没有任何树木运动的形态,只有局部极值的一些“丛生”是明显的。 然而,与之前研究的算法相比,显而易见其收敛是高品质的。 结果的稳定重现性也值得注意。


rastrigin

  Rastrigin 测试函数上的 SSG

forest

  基于 Forest 测试函数的 SSG

megacity

  基于 Megacity 测试函数上的 SSG


我们继续讨论 SSG 算法的结果。 肯定有话要说。 该算法已经令人欣慰地冲进了评级的第一名,将竞争对手甩在了后面! 该算法不直接使用适应度知识来修改决策树。 只需要对子花园和父花园的适应度进行排序,如此该算法能够在测试中展现出刷新认知的结果就更加令人惊讶了。

这就像盲人队伍在定向越野中击败了视力正常的队伍一样。 该算法在六项测试中的四项中领先于表格中的参与者,而在它不是领先者的测试中也不甘落后。 SSG 在 Megacity 离散函数上表现出最令人印象深刻的领先优势,比最接近的竞争对手 HS 高出近 60%! 这证明了该算法出色的可扩展性。 在 “锐利” 的 Forest 测试函数上也观察到了最佳的可伸缩性结果。 SSG 在该测试中的表现比最佳竞争对手(ACOm)高出近 30%。

算法

说明

Rastrigin

Rastrigin 最终

Forest

Forest 最终

Megacity (离散)

Megacity 最终

最终结果

10 参数 (5 F)

50 参数 (25 F)

1000 参数 (500 F)

10 参数 (5 F)

50 参数 (25 F)

1000 参数 (500 F)

10 参数 (5 F)

50 参数 (25 F)

1000 参数 (500 F)

SSG

树苗播种和生长

1.00000

1.00000

0.65914

2.65914

0.70823

0.94522

1.00000

2.65345

0.71532

0.85412

1.00000

2.56944

100.000

HS

和弦搜索

0.99676

0.95282

0.57048

2.52006

1.00000

0.98931

0.44806

2.43736

1.00000

1.00000

0.41537

2.41537

93.370

ACOm

蚁群优化 M

0.34611

0.17985

0.20182

0.72778

0.85966

1.00000

0.77362

2.63327

1.00000

0.88484

0.05606

1.94090

66.407

IWO

入侵杂草优化

0.95828

0.67083

0.35295

1.98207

0.68718

0.46349

0.31773

1.46840

0.75912

0.39732

0.33289

1.48933

61.691

COAm

杜鹃优化算法 M

0.92400

0.46794

0.30792

1.69987

0.55451

0.34034

0.16526

1.06012

0.67153

0.30326

0.17083

1.14561

48.226

FAm

萤火虫算法 M

0.59825

0.33980

0.20290

1.14095

0.47632

0.42299

0.49790

1.39721

0.21167

0.25143

0.35258

0.81568

41.042

ABC

人工蜂群

0.78170

0.32715

0.24656

1.35541

0.50591

0.21455

0.13344

0.85390

0.47444

0.23609

0.13926

0.84979

37.204

BA

蝙蝠算法

0.40526

0.63761

1.00000

2.04287

0.15275

0.17477

0.25989

0.58741

0.15329

0.06334

0.17371

0.39034

36.703

GSA

引力搜索算法

0.70167

0.45217

0.00000

1.15384

0.26854

0.36416

0.33204

0.96475

0.51095

0.32436

0.00000

0.83531

35.834

BFO

细菌觅食优化

0.67203

0.30963

0.13988

1.12154

0.35462

0.26623

0.20652

0.82736

0.42336

0.30519

0.18932

0.91786

34.700

MA

猴子算法

0.33192

0.33451

0.17340

0.83983

0.03684

0.07891

0.08932

0.20508

0.05838

0.00383

0.10720

0.16941

13.185

FSS

鱼群搜索

0.46812

0.25337

0.13383

0.85532

0.06711

0.05013

0.06516

0.18240

0.00000

0.00959

0.08283

0.09242

12.089

PSO

粒子群优化

0.20449

0.08200

0.08478

0.37127

0.13192

0.10486

0.21738

0.45415

0.08028

0.02110

0.01957

0.12095

9.696

RND

随机

0.16826

0.09743

0.09495

0.36065

0.07413

0.04810

0.04715

0.16938

0.00000

0.00000

0.04922

0.04922

4.916

GWO

灰狼优化器

0.00000

0.00000

0.02672

0.02672

0.00000

0.00000

0.00000

0.00000

0.18977

0.03645

0.02557

0.25179

1.000



总结

SSG 特点:对优化函数的可微性和连续性没有要求,对所应用的表现和编码类型没有限制。 该算法不使用独立代理者的适应度信息和整体最佳解。 感谢这些功能,SSG 可以轻松应用于各种优化问题,包括非常复杂的问题。 SSG 肯定可以推荐针对交易者的问题和机器学习。 在撰写本文时,树苗播种和成长算法在收敛品质、结果稳定性、和可扩展性方面是无可争议的领先者。

图例. 2 展示算法的测试结果

图表

图例 2. 算法测试结果的直方图

SSG 算法的优点和缺点:

优点:
1. 易于实现。
2. 在所有类型的函数上都具有出色的收敛性,无一例外。
3. 令人印象深刻的可扩展性。

缺点:
1. 自定义选项太多,尽管它们直观清晰。

每篇文章都提供一个存档,其中包含所有以前文章的算法代码的当前更新版本。 本文基于作者积累的经验,仅代表他的个人观点。 结论和判断基于实验。


本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/12268

附加的文件 |
学习如何基于斐波那契(Fibonacci)设计交易系统 学习如何基于斐波那契(Fibonacci)设计交易系统
在本文中,我们将继续如何基于最流行的技术指标创建交易系统的系列文章。 这次一个新的技术工具,即斐波那契(Fibonacci),我们将学习如何基于该技术指标设计交易系统。
数据科学和机器学习(第 13 部分):配合主成分分析(PCA)改善您的金融市场分析 数据科学和机器学习(第 13 部分):配合主成分分析(PCA)改善您的金融市场分析
运用主成分分析(PCA)彻底革新您的金融市场分析! 发现这种强大的技术如何解锁数据中隐藏的形态,揭示潜在的市场趋势,并优化您的投资策略。 在本文中,我们将探讨 PCA 如何为分析复杂的金融数据提供新的视角,揭示传统方法会错过的见解。 发掘 PCA 应用于金融市场数据如何为您带来竞争优势,并帮助您保持领先地位。
开发回放系统 — 市场模拟(第 03 部分):调整设置(I) 开发回放系统 — 市场模拟(第 03 部分):调整设置(I)
我们从梳理当前状况开始,因为我们尚未以最好的方式开始。 如果我们现在不这样做,我们很快就会遇到麻烦。
开发回放系统 — 市场模拟(第 02 部分):首次实验(II) 开发回放系统 — 市场模拟(第 02 部分):首次实验(II)
这一次,我们尝试换一种不同的方式来实现 1 分钟的目标。 然而,这项任务并非如人们想象的那么简单。