一、Nelder-Mead算法介绍

Nelder-Mead算法主要应用于求解一些非线性(nonliner)、导函数未知的最大值或最小值问题。本文利用Nelder-Mead算法求解函数最小值问题。

当应用Nelder-Mead时,若函数有n个变量,则数据集合(simplex)需要构建n+1个元素。利用这n+1个元素,不停地替换掉函数值最大(小)的元素,同时维护更新中心点的值,当最终的函数值满足容忍条件时即可得出近似解的结果。

算法的流程如下:

1. 构建变量集合A = {

二元线性函数 python python二元函数如何编写_python二元函数如何编写

},集合中的每个元素是一个多维的集合,例如对于

二元线性函数 python python二元函数如何编写_最小值_02


二元线性函数 python python二元函数如何编写_最小值_03

为1维。且该集合满足

二元线性函数 python python二元函数如何编写_github_04


2. 计算中心点

二元线性函数 python python二元函数如何编写_python二元函数如何编写_05

,即A中每个元素对应的每一维的平均值。

3. 由于在之前的集合A中,已经可以知道最末尾的变量对应的函数值是最大的,因此对其进行替换,每一次替换后都要更新一次中心点的值。替换的方法共有四种:

(1)反射,将

二元线性函数 python python二元函数如何编写_最小值_06


二元线性函数 python python二元函数如何编写_python二元函数如何编写_05

为原点映射到对应的

二元线性函数 python python二元函数如何编写_最小值_03

倍距离位置,其中

二元线性函数 python python二元函数如何编写_最小值_09


(2)扩展反射,将

二元线性函数 python python二元函数如何编写_最小值_06


二元线性函数 python python二元函数如何编写_python二元函数如何编写_05

为原点映射到对应的

二元线性函数 python python二元函数如何编写_github_12

倍距离位置,其中

二元线性函数 python python二元函数如何编写_最小值_13


(3)缩小距离,将

二元线性函数 python python二元函数如何编写_最小值_06


二元线性函数 python python二元函数如何编写_python二元函数如何编写_05

为原点缩小到

二元线性函数 python python二元函数如何编写_最小值_16

倍距离位置,其中

二元线性函数 python python二元函数如何编写_python二元函数如何编写_17


(4)缩小距离,将

二元线性函数 python python二元函数如何编写_最小值_06


二元线性函数 python python二元函数如何编写_python二元函数如何编写_19

为原点缩小到

二元线性函数 python python二元函数如何编写_最小值_20

倍距离位置,其中

二元线性函数 python python二元函数如何编写_二元线性函数 python_21


注意(3)和(4)中映射操作采用的原点不同,

二元线性函数 python python二元函数如何编写_最优解_22

的标准取值为

二元线性函数 python python二元函数如何编写_最优解_23

。在四种替换方法中选择出相对更大(小)的

二元线性函数 python python二元函数如何编写_最优解_24

,利用

二元线性函数 python python二元函数如何编写_github_25

替换掉之前最大的

二元线性函数 python python二元函数如何编写_最小值_06


注:四种替换方法从(1)到(4)执行,一旦满足替换条件则不向下继续求解替换,而是重新回归步骤1。

4. 重复上述过程,直到集合A中的值满足容忍条件即可停止,并认为已经定位到了可能的最大(小)值的点。(个人理解是会在一定情况下出现局部最优解的情况,即一直重复(1)和(2)的替换方法)。

为了使结果尽可能避免是局部最优解,在构建初始集(initial simplex)非常关键。当初始集构造范围过小时,大概率会出现局部解而非全局解,因此在构建初始集合时,要求各个元素构成的区域是非零容积。

二、Python实现

首先定义需要求解的目标函数:

def func(x, y):#目标函数
result = math.pow(x - y, 2) + math.pow(x - 2, 2) + math.pow(y - 3, 4)
return result

个人设计的存储结构是dict{

二元线性函数 python python二元函数如何编写_二元线性函数 python_27


二元线性函数 python python二元函数如何编写_最优解_28

} 
def get_dict(res_dict):#获取坐标:值的dict
for i in range(4):
x = random.randint(-10, 10)
y = random.randint(-10, 10)
result = func(x, y)
loc = (x, y)
res_dict[loc] = result
return res_dict

由于在算法中对函数值排序的作用仅在于获取最大值和最小值对应的

二元线性函数 python python二元函数如何编写_最小值_03

,因此只需要得到dict中最大和最小value对应的key。因此设计两个函数返回对应的index或对应的key。本文中返回对应的index。

def get_max():
...
return index_max
def get_min():
...
return index_min

接下来设计5个函数,分别用作求中间值mean,以及4种探索方法计算对应的z1, z2, z3和z4。此处对算法进行了一点更改,即直接比较4种方法的值获得一个相对最优的解。目前测试的结果也能达到该算法执行的结果。

result_list = []#分析四种分散方法对应的z函数值
result_list.append(get_z1(index_max, mean, res_dict))
result_list.append(get_z2(index_max, mean, res_dict))
result_list.append(get_z3(index_max, mean, res_dict))
result_list.append(get_z4(index_max, index_min, mean, res_dict))
index = 0
flag = 0
min = result_list[0][1]#得到最小的函数值
for r in result_list:#获取最小的z值对应的坐标进行替换
if result_list[flag][1] <= min:
min = result_list[index][1]
index = flag
flag += 1
else:
flag += 1
z = result_list[index][1]
z_cord = tuple(result_list[index][0])#(x,y)

最后替换掉集合中的点,不断循环更新。最后满足容忍条件时结束循环。

代码详情见:https://github.com/olddaddy/data_mining_1.git