1. 程式人生 > 實用技巧 >二維爬山掃描演算法求最大值

二維爬山掃描演算法求最大值

#測試演算法
import numpy as np
pointdata=np.random.randint(1,100,size=(1000,2))
print(pointdata)
score=np.random.randn(1000)
score=score.reshape(-1,1)
print(score)
finaldata=np.hstack((pointdata,score))
print(finaldata)

#實時輸出座標軸x,y
def output(x,y):
return -x**2-y**2-x*y+4*x
'''
def output(x,y):
score=finaldata(x,y)
return score
'''

def test(x0,y0,fanx,fany):
#定義初始值的大小
point_x=x0
point_y=y0

step=0.001
point_history=[]
score_history=[]

i=0
while (point_x<fanx[1] and point_x>fanx[0]) and (point_y<fany[1] and point_y>fany[0]) and i<1e4:
x0=point_x
y0=point_y
while point_x<fanx[1] and point_x>fanx[0]:

last_point_x=point_x
gradient = (output(point_x+step, point_y) - output(point_x, point_y)) / step
point_x=point_x+step*np.sign(gradient)

if abs(output(point_x,point_y)-output(last_point_x,point_y))<0.0001:
print(point_x)
point_history.append((point_x,point_y))
score_history.append(output(point_x,point_y))
break

while point_y<fany[1] and point_y>fany[0]:

last_point_y = point_y
gradient = (output(point_x, point_y+step) - output(point_x, point_y)) / step
point_y = point_y + step * np.sign(gradient)

if abs(output(point_x,point_y)-output(point_x,last_point_y))<0.00001:
point_history.append((point_x, point_y))
score_history.append(output(point_x, point_y))
print(point_y)
break

if abs(output(point_x, point_y) - output(x0, y0)) < 0.0000001 or abs(point_x-x0) < 0.00001:
break
i=i+1
print(point_x, point_y,x0, y0)

test(2,8,[-10,10],[-10,10])

# 畫出影象如下進行檢查
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from matplotlib import pyplot as plt

fig = plt.figure(figsize=(10,6))
ax = Axes3D(fig)
x = np.arange(-10, 10, 0.5)
y = np.arange(-10, 10, 0.5)
X, Y = np.meshgrid(x, y)
Z =-X**2 - Y**2-X*Y+4*X
plt.xlabel('x')
plt.ylabel('y')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='rainbow')
plt.show()
print(Z)
print(np.max(Z))

二維爬山掃描演算法

  1. 演算法思想:

爬山掃描演算法主體思想是採用分軸迭代的思路,對每個軸依次進行最優值的尋找,然後不斷進行迴圈迭代,最後找到整體最大值時的引數組合。其中,分軸迭代演算法主要思想是在限制另外一個軸資料一定的情況下使用單軸梯度上升法求得單軸最大值時的變數取值。

另外,由於使用場景是實時傳出的測量資料,所以資料之間不存在具體的二維函式表示式,只是由資料不斷測量累計的資料集合。在這種情況下,使用梯度上升方法求最值時,不能用求導的形式來求得,只可使用梯度代替方法,即:

另外,由於資料不是離線進行積累的,所以在使用梯度上升法時不能直接在原來的資料初始點上加以梯度*步長,因為在資料初始點開始時一般梯度值很大,所以單軸資料更替變化太大,新的資料點下的指標實時測量不到,所以為了保證在實時中資料的可測量性,我們最好使用固定的步長(並且資料更新需要慢於實時測量的速度)來進行單軸資料的更替,即單軸資料更替表示式為:

其中sign(x)是取數字的正負號函式:

使用sign(x)*gradient更替的好處就是單軸自變數依舊可以按照梯上升的方向進行最大值的尋找,並且可以控制步長大小來和實時測量傳輸資料的速度進行匹配。

  1. 演算法步驟:

整體演算法主要可以分為以下幾步:

(1) 在約束範圍裡初始化開始點point();

(2) 判斷初始點是否在規定的引數範圍中,如果在,則往下進行第三步;不在則結束演算法;

(3) 固定y軸不變,進行x軸的移動,基於實時測量的資料進行梯度上升的最大值尋找,直到達到x軸的指標最高點(或者接近最高點的位置),記錄此時的,其核心在於:

y軸固定不變,

(4) 固定x軸不變,即x=,之後基於y軸利用梯度上升法進行y軸指標最大值的尋找,並將達到最大值時的y記為,此時核心是:

x軸固定不變,

(5) 迴圈(2)(3)步驟,直到每一次x,y軸迭代前後指標值相差小於一定的閾值時,可以認為已經達到最大值(此外,為了防止迭代次數太多,可以設定一定的迭代次數限制引數);

(6) 結束演算法,輸此時的x和y的值。

整體的演算法流程如下圖所示:

圖 二維掃描爬山演算法流程圖

  1. 演算法測試:

(1)對於基礎測量的資料集形成的如下二維影象:

圖 二維資料點集影象

x和y的約束範圍為-10到10,此時利用演算法求得最優解為:x=y=0,最優解為0,是正確的;

(2)換一種資料集形成的影象形式:

x和y的約束範圍為-10到10,此時利用演算法求得最優解為:x=2.67,y=-1.33,最優解為5.3,是正確的;

  1. 原始碼:

#實時輸出測量值函式(x,y為位置座標,返回的score為此位置處的指標測量值大小)

'''

def output(x,y):

score=finaldata(x,y)

return score

'''

#整體的掃描演算法函式

def test(x0,y0,fanx,fany):

#定義初始位置x0,y0

point_x=x0

point_y=y0

#定義爹迭代掃描的步長大小step

step=0.001

point_history=[]

score_history=[]

#定義目前的迭代次數

i=0

#定義最大的迭代次數

number=1e4

#判斷繼續進行迭代的條件:在約束範圍裡並且迭代次數小於規定次數

while (point_x<fanx[1] and point_x>fanx[0]) and (point_y<fany[1] and point_y>fany[0]) and i<number:

x0=point_x

y0=point_y

#固定y軸,x軸單軸的最大值掃描

while point_x<fanx[1] and point_x>fanx[0]:

last_point_x=point_x

gradient = (output(point_x+step, point_y) - output(point_x, point_y)) / step

point_x=point_x+step*np.sign(gradient)

if abs(output(point_x,point_y)-output(last_point_x,point_y))<0.0001:

print(point_x)

point_history.append((point_x,point_y))

score_history.append(output(point_x,point_y))

break

#固定x軸,y軸單軸的最大值掃描

while point_y<fany[1] and point_y>fany[0]:

last_point_y = point_y

gradient = (output(point_x, point_y+step) - output(point_x, point_y)) / step

point_y = point_y + step * np.sign(gradient)

if abs(output(point_x,point_y)-output(point_x,last_point_y))<0.00001:

point_history.append((point_x, point_y))

score_history.append(output(point_x, point_y))

print(point_y)

break

#判斷一次x,y軸迭代之後指標值的差距是否足夠小,達到閾值之後預設已經到最高點或者接近最高點

if abs(output(point_x, point_y) - output(x0, y0)) < 0.0000001 or abs(point_x-x0) < 0.00001:

break

i=i+1

print(point_x, point_y) #輸出最終最高點的位置座標xy