具有自定义负对数似然函数的 mle 内存错误

mle memory error with custom negative log-likelihood function

我正在尝试将 'mle' 与自定义负对数似然函数一起使用,但出现以下错误:

Requested 1200000x1200000 (10728.8GB) array exceeds maximum array size preference (15.6GB). This might cause MATLAB to become unresponsive.

我使用的数据是一个 1x1200000 二进制数组(我必须将其转换为双精度数组),该函数有 10 个参数:一个用于数据,3 个已知参数,6 个待优化。我尝试将 'OptimFun' 设置为 'fminsearch' 和 'fmincon'。此外,使用 'fminsearch' 和 'fminunc' 而不是 'mle' 优化参数效果很好。
问题发生在 'checkFunErrs' 函数中,在 'mlecustom.m' 文件中(在第 173 行调用,在第 705 行实际出错)。
使用 'fminunc' 我可以计算出最佳参数,但它没有给我置信区间。有没有办法规避这个?还是我做错了什么?
感谢您的帮助。

T_1 = 50000;
T_2 = 100000;
npast = 10000;
start = [0 0 0 0 0 0];
func = @(x, data, cens, freq)loglike(data, [x(1) x(2) x(3) x(4) x(5) x(6)],...
                        T_1, T_2, npast);
params = mle(data, 'nloglf', func, 'Start', start, 'OptimFun', 'fmincon');
% Computes the negative log likehood
function out = loglike(data, params, T_1, T_2, npast)
    size = length(data);
    if npast == 0
        past = 0;
    else
        past = zeros(1, size);
        past(npast+1:end) = movmean(data(npast:end-1),[npast-1, 0]); % Average number of events in the previous n years
    end
    lambda = params(1) + ...
        (params(2)*cos(2*pi*(1:size)/T_1)) + ...
        (params(3)*sin(2*pi*(1:size)/T_1)) + ...
        (params(4)*cos(2*pi*(1:size)/T_2)) + ...
        (params(5)*sin(2*pi*(1:size)/T_2)) + ...
        params(6)*past;
    out = sum(log(1+exp(lambda))-data.*lambda);
end

您的问题是内置 mle 函数的第 228 行(从 MATLAB R2017b 开始),它发生在调用自定义函数之前:

data = data(:);

输入变量data在没有警告的情况下转换为列数组。这通常是为了确保所有进一步的计算对输入向量的方向都是稳健的。

但是,这会给您带来问题,因为您的自定义函数假定 data 是一个行向量,特别是这一行:

out = sum(log(1+exp(lambda))-data.*lambda);

由于 implicit expansion,当行向量 lambda 和列向量 data 相互作用时,根据错误消息,您会得到一个巨大的方阵。

添加这两行以明确表明两者都是列向量解决了这个问题,避免了隐式扩展,并按照您的预期逐元素应用计算。

lambda = lambda(:);
data = data(:);

所以你的函数变成了

function out = loglike(data, params, T_1, T_2, npast)
    N = length(data);
    if npast == 0
        past = 0;
    else
        past = zeros(1,N);
        past(npast+1:end) = movmean(data(npast:end-1),[npast-1, 0]); % Average number of events in the previous n years
    end
    lambda = params(1) + ...
        (params(2)*cos(2*pi*(1:N)/T_1)) + ...
        (params(3)*sin(2*pi*(1:N)/T_1)) + ...
        (params(4)*cos(2*pi*(1:N)/T_2)) + ...
        (params(5)*sin(2*pi*(1:N)/T_2)) + ...
        params(6)*past;
    lambda = lambda(:);
    data = data(:);
    out = sum(log(1+exp(lambda))-data.*lambda);
end

另一种方法是重写您的函数,使其使用列向量,但您使用 (1:N) 步骤和 movmean 中的串联创建新的行向量。建议的方法可以说是“更懒惰”,但对行或列输入也很稳健。

另请注意,我已将您的变量名称从 size 更改为 N,因为 size 是一个内置函数,您应该避免隐藏。