在 SciPy optimize.minimize 中优化 objective 函数

Optimizing objective function in SciPy optimize.minimize

res_M = minimize(L_M, x0=x_M, args=(data, w_vector),
                 method='L-BFGS-B', bounds=[(0.001, 1), (0.001, 1), (0.001, 1)])

def L_M(x, data, w_vector):    
    sum = 0
    for i in range(len(data)):
        sum += w_vector[i]*(data[i][0]*np.log(x[0])+data[i][1]*np.log(x[1])+data[i][2]*np.log(x[2]))
    return -1*sum

作为期望最大化 (EM) 算法的一部分,我在 M 步中调用 SciPy 的 optimize.minimize 函数。 x_M是0到1之间的三个值,最初都是0.5。 w_vectors 在 E-Step 中计算,由数据集长度的 NumPy 一维数组组成,浮点数在 0 到 1 范围内。数据集中的每一行都是 0 之间的三个整数特征值和 3,例如 [1 0 2].

objective 函数中的 for 循环正在减慢速度。我想改用矢量化计算来优化它。我尝试了以下方法,但它改变了结果:

def L_M(x, data, w_vector):
        length = len(data)        
        a_i = data[np.arange(length)][0].sum()
        f_i = data[np.arange(length)][1].sum()
        l_i = data[np.arange(length)][2].sum()
        sum = (w_vector[np.arange(length)].sum())*(a_i*np.log(x[0])+f_i *np.log(x[1])+l_i*np.log(x[2]))
        return -1*sum

最小化函数被调用了很多次,我希望在一些非常大的数据集上对其进行测试,所以任何关于如何重写它的想法都将不胜感激。

您应该将所有数组转换为 NumPy 数组,然后可以按如下方式实现:

import numpy as np

data = np.array([[1, 0, 2], [2, 1, 0]])
w_vector = np.array([0, 1]

def L_M(x : np.ndarray, data : np.ndarray, w_vector : np.ndarray):    
    result = np.sum(w_vector * np.sum(data*np.log(x), axis = 1))
    return -result

这部分代码 ((data[i][0]*np.log(x[0])+data[i][1]*np.log(x[1])+data[i][2]*np.log(x[2]))),其中第 i 个位置的 data 的每个元素与 x 的每个元素的对数相乘,然后取所有三个元素的总和, 被 np.sum(data*np.log(x), axis = 1) 取代,其中实现了 element-wise 乘法(因为这些是 np.array)并且求和 row-wise 并且每行的总和在 1D- 中返回数组。

之后,这个数组乘以w_vector(因为它们具有相同的长度并且是np.array,element-wise乘法是可能的)。

最后,将结果数组的总和保存到result。为了优化,将 x_M 也作为 NumPy 数组传递:

from scipy.optimize import minimize

x_M = np.array([0.5, 0.5, 0.5])

res_M = minimize(L_M, x0=x_M, args=(data, w_vector),
                 method='L-BFG-B', bounds=[(0.001, 1), (0.001, 1), (0.001, 1)])

P.S.: 避免使用像 sum 这样的变量名,因为它已经是一个 Python 函数,恕我直言,这不是一个好的做法。