构造函数 - 给定最小值的 f(x,y) (Python)

数据挖掘 Python 优化
2022-02-19 04:56:24

问题陈述:

我需要构造一个函数 f(x,y),其中有 3 个最小值。2个本地和1个全局,写在下面。

局部变量是:z = f(0.2,0.3) = 0.7 | z = f(0.6,0.8) = 0.8

全局为:z = f(0.85,0.5) = 0.6


到目前为止我尝试过的

我尝试过多项式回归来构建估计给定最小点的特征。但是,估计函数 z = f(x,y) 只是遍历所有给定的最小点,而不将它们视为最小值。我需要一种方法,通过它我可以构造一个具有上述 3 个最小值的函数。如果您能提供您的方法的代码片段,我会非常高兴。作为一种编程语言,我使用 Python。

代码

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D

degree = 6


def func(x1, x2):
    arr = []
    for i in range(degree, 0, -1):
        arr.append(x1 ** i)

    for i in range(degree, 0, -1):
        arr.append(x2 ** i)

    arr.append(1)

    return np.array(arr)


def der_func(x1, x2):
    arr1 = []
    arr2 = []
    for i in range(degree - 1, -1, -1):  
        arr1.append((i + 1) * x1 ** i)  

    for i in range(degree + 1):
        arr1.append(0)

    for i in range(degree):
        arr2.append(0)

    for i in range(degree - 1, -1, -1):
        arr2.append((i + 1) * x2 ** i)

    arr2.append(0)

    return np.array([arr1, arr2])


given_x = np.array([[0.2, 0.3],
                    [0.6, 0.8],
                    [0.85, 0.5]])

given_y = np.array([0.7, 0.8, 0.6])

data_x = []
data_y = []

for i in range(len(given_x)):
    x1x2 = given_x[i]

    data_x.append(func(x1x2[0], x1x2[1]))
    data_y.append(given_y[i])

    if i < 3: # in case there's more than 3 data point in given_x
        data_x.append(der_func(x1x2[0], x1x2[1])[0])
        data_y.append(0)

        data_x.append(der_func(x1x2[0], x1x2[1])[1])
        data_y.append(0)

data_x = np.array(data_x)
data_y = np.array(data_y)

w = np.linalg.inv(data_x.T @ data_x) @ data_x.T @ data_y
pred_y = data_x @ w

cost = np.mean((data_y - pred_y) ** 2)
print("Cost | ", cost)

#######################################

X = np.linspace(0, 1, 100)
Y = np.linspace(0, 1, 100)

X, Y = np.meshgrid(X, Y)
Z = np.zeros(np.shape(X))
for i in range(len(X)):
    for j in range(len(X[0])):
        Z[i, j] = np.array([func(X[i, j], Y[i, j])]) @ w

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.contour(X, Y, Z, 150)
ax.scatter(given_x[:3, 0], given_x[:3, 1], given_y[:3])
plt.show()

3个回答

一种方法是定义仅在“最小”点附近非零的函数,然后添加它们。目标是避免重叠,这样与一个点关联的函数不会修改您的全局函数在其他点周围的值。

import numpy as np

def func0(x1):
    lim = 0.01
    dist = x1*x1
    if dist<lim:
        value = np.exp(-dist/(lim-dist))
    else: 
        value = 0
    return value

这将为您提供具有良好属性的一维函数(0 处的值 1,0 邻域外的 0):

x = np.linspace(-1, 1, 1000)
z = np.array([func0(i) for i in x])
Z = z.reshape(1000)

plt.plot(Z)
plt.show()

在此处输入图像描述

修改它以获得以 (a,b) 为中心的二维函数:

def func(x1,x2):
    a = 0
    b = 0
    lim = 0.01
    dist = (x1-a)*(x1-a) + (x2-b)*(x2-b)
    if dist<lim:
        value = np.exp(-dist/(lim-dist))
    else: 
        value = 0
    return value 

这将为您提供 2d 功能:

x = y = np.linspace(-1, 1, 100)
z = np.array([func(i,j) for j in y for i in x])
Z = z.reshape(100, 100)

x, x = np.meshgrid(x, y)

plt.imshow(Z,extent=(x.min(), x.max(), y.min(), y.max()))
plt.colorbar()
plt.show()

在此处输入图像描述

然后构建与您的点相关的三分球功能。

def func1(x1,x2):
    a = 0.2
    b = 0.3
    lim = 0.01
    dist = (x1-a)*(x1-a) + (x2-b)*(x2-b)
    if dist<lim:
        value = np.exp(-dist/(lim-dist))
    else: 
        value = 0
    return value

def func2(x1,x2):
    a = 0.6
    b = 0.8
    lim = 0.01
    dist = (x1-a)*(x1-a) + (x2-b)*(x2-b)
    if dist<lim:
        value = np.exp(-dist/(lim-dist))
    else: 
        value = 0
    return value

def func3(x1,x2):
    a = 0.85
    b = 0.5
    lim = 0.01
    dist = (x1-a)*(x1-a) + (x2-b)*(x2-b)
    if dist<lim:
        value = np.exp(-dist/(lim-dist))
    else: 
        value = 0
    return value

并将它们相加(直到确定兴趣点值的系数)以形成一个全局函数:

def global_func(x,y):
    return 1-0.3*func1(x,y)-0.2*func2(x,y)-0.4*func3(x,y)

这会给你:

x = y = np.linspace(0, 1, 1000)
z = np.array([global_func(i,j) for j in y for i in x])
Z = z.reshape(1000, 1000)

x, x = np.meshgrid(x, y)

plt.imshow(Z,extent=(x.min(), x.max(), y.min(), y.max()))
plt.colorbar()
plt.show()

在此处输入图像描述

最后,您可以检查:

print(global_func(0.2,0.3))
print(global_func(0.6,0.8))
print(global_func(0.85,0.5))

返回:

0.7
0.8
0.6

通过构造,您具有具有所有预期属性的连续函数。

如果您对它在很多域上保持不变不满意,您可以修改各个函数,使它们不会停留在极限:

value = np.exp(-dist)

在您的全局函数中,确定哪个“最小”点是最近的,并且仅根据哪个点最近应用形式为 1-coef * funci 的函数。这样各个函数就不会重叠,因此不会围绕其他“最小”点修改全局函数的值。

由于您有确切的规格,您可以直接硬编码答案:

def f(x: float, y: float) -> float:
    "Deterministically return the value of z."
    if (x == 0.85) and (y == 0.5):
        return 0.6 # Global minimum 
    elif (x == 0.2) and (y == 0.3):
        return 0.7 # Local minimum
    elif (x == 0.6) and (y == 0.8):
        return 0.8 # Local minimum
    else: 
        return 0.9 # Not a minimum

添加作为附加约束,一阶导数为 0,并且它大于/小于区间上的所有值,暗示最大值或最小值。