scipy 求解非线性方程组(潜变量的乘积)

v1l68za4  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(97)

我正在尝试用Python求解一个方程组,其中每个结果都是两个潜在变量之间的一系列乘积的总和:

其中itj具有更多的值(例如,每个30)(在2和5之间)。所以如果I和T取30个值,J取4个值,那么会有900个结果和240个未知数。理想情况下,我想用最小二乘的方法来求解伽马和η的值。我知道需要有一些正常化。
这是一个固定函数的标准问题,还是我需要使用一般的最小化技术?

pgccezyw

pgccezyw1#

认识到你的“一系列产品的总和”实际上只是一个矩阵产品。
下面的例子并不能很好地拟合,但这可能是因为你的问题是高度超定的:

import numpy as np
from scipy.optimize import minimize, check_grad
from numpy.random._generator import default_rng

I = 30
J = 5
T = 27

rand = default_rng(seed=0)
y = rand.uniform(low=-1, high=1, size=(I, T))

def factors_from_flat(params: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
    gamma = np.resize(params[:I*J], (I, J))
    eta = np.resize(params[-J*T:], (J, T))
    return gamma, eta

def matrix_cost(gamma: np.ndarray, eta: np.ndarray) -> np.ndarray:
    return gamma @ eta - y

def scalar_cost(params: np.ndarray) -> float:
    gamma, eta = factors_from_flat(params)
    error = matrix_cost(gamma, eta).ravel()
    return error.dot(error)

def jacobian(params: np.ndarray) -> float:
    gamma, eta = factors_from_flat(params)
    error = matrix_cost(gamma, eta)
    jac = np.empty(I*J + J*T)
    jac[:I*J] = (error @ eta.T).ravel()
    jac[-J*T:] = (gamma.T @ error).ravel()
    return 2*jac

x0 = np.full(I*J + J*T, 1/np.sqrt(I*J*T))
err = check_grad(func=scalar_cost, grad=jacobian, x0=x0)
assert err < 1e-2
    
result = minimize(fun=scalar_cost, x0=x0, jac=jacobian)
assert result.success, result.message

gamma_est, eta_est = factors_from_flat(result.x)
y_est = gamma_est @ eta_est

雅可比矩阵很乐意指向一个最小值,并且该最小值可能是局部的,这可能符合您的目的。可以预见的是,对于具有条带模式的数据,这种方法的性能要好得多,如

y = rand.uniform(low=-0.01, high=0.01, size=(I, T))
y += rand.uniform(low=-1, high=1, size=I)[:, np.newaxis]

或甚至双轴条纹:

y = rand.uniform(low=-0.01, high=0.01, size=(I, T))
y += rand.uniform(low=-1, high=1, size=I)[:, np.newaxis]
y += rand.uniform(low=-1, high=1, size=T)[np.newaxis, :]

相关问题