R中多项式的MLE的简单数值估计问题

时间:2019-09-16 10:09:57

标签: r optimization statistics mle

我正在尝试为多项式分布建立简单的数值MLE估计。

多项式有一个约束-所有像元概率都需要加起来为一个。

通常具有此约束的方法是将一个概率重新表示为(1-其他概率之和)

但是,当我运行此命令时,在优化过程中出现了问题,对数可能为负值。

关于如何解决此问题的任何想法?我尝试使用另一个优化程序包(Rsolnp)并起作用,但是我试图使其与简单的默认R optim一起工作,以避免约束/非线性优化。

这是我的代码(我知道我可以在这种特殊情况下分析得出结果,但这是一个玩具示例,我的实际问题比这里要大)。

set.seed(1234)
test_data <- rmultinom(n = 1, size = 1000, prob = rep(1/4, 4))
N <- test_data
loglik_function <- function(theta){
  output <- -1*(N[1]*log(theta[1]) + N[2]*log(theta[2]) + N[3]*log(theta[3]) + N[4]*log(1- sum(theta)))
  return(output)
}

startval <- rep(0.1, 3)

my_optim <- optim(startval, loglik_function, lower = 0.0001, upper = 0.9999, method = "L-BFGS-B")

任何想法或帮助将不胜感激。谢谢

1 个答案:

答案 0 :(得分:3)

充分抬头:我知道您问过(受限)的ML估计,但是如何使用贝叶斯方法àla Stan / rstan做这件事。如果没有用/遗漏了点,我将删除它。

  1. 该模型只有几行代码。

    library(rstan)
    
    model_code <- "
    data {
        int<lower=1> K;           // number of choices
        int<lower=0> y[K];        // observed choices
    }
    
    parameters {
        simplex[K] theta;         // simplex of probabilities, one for every choice
    }
    
    model {
        // Priors
        theta ~ cauchy(0, 2.5);   // weakly informative
        // Likelihood
        y ~ multinomial(theta);
    }
    
    generated quantities {
        real ratio;
        ratio = theta[1] / theta[2];
    }
    "
    

    您可以看到使用Stan数据类型thetasimplex上实现单纯形约束有多么容易。在Stan语言中,simplex使您可以轻松实现probability (unit) simplex

    enter image description here

    其中K表示参数数(此处为选择数)。

    还要注意如何使用generated quantities代码块根据参数(此处为ratiotheta[1])来计算派生数量(此处为theta[2])。由于我们可以访问所有参数的后验分布,因此计算派生数量的分布很简单。

  2. 然后我们将模型拟合到您的test_data

    fit <- stan(model_code = model_code, data = list(K = 4, y = test_data[, 1]))
    

    并显示参数估计值的摘要

    summary(fit)$summary
    #                 mean      se_mean         sd          2.5%           25%
    #theta[1]     0.2379866 0.0002066858 0.01352791     0.2116417     0.2288498
    #theta[2]     0.26 20013 0.0002208638 0.01365478     0.2358731     0.2526111
    #theta[3]     0.2452539 0.0002101333 0.01344665     0.2196868     0.2361817
    #theta[4]     0.2547582 0.0002110441 0.01375618     0.2277589     0.2458899
    #ratio        0.9116350 0.0012555320 0.08050852     0.7639551     0.8545142
    #lp__     -1392.6941655 0.0261794859 1.19050097 -1395.8297494 -1393.2406198
    #                   50%           75%         97.5%    n_eff      Rhat
    #theta[1]     0.2381541     0.2472830     0.2645305 4283.904 0.9999816
    #theta[2]     0.2615782     0.2710044     0.2898404 3822.257 1.0001742
    #theta[3]     0.2448304     0.2543389     0.2722152 4094.852 1.0007501
    #theta[4]     0.2545946     0.2638733     0.2822803 4248.632 0.9994449
    #ratio        0.9078901     0.9648312     1.0764747 4111.764 0.9998184
    #lp__     -1392.3914998 -1391.8199477 -1391.3274885 2067.937 1.0013440
    

    以及显示theta参数的点估计和CI的图

    plot(fit, pars = "theta")
    

    enter image description here


更新:使用maxLik

的受限ML估计

实际上,您可以使用maxLik库提供的方法来实现约束ML估计。我发现它有点“麻烦”,因为收敛似乎对起始值和所用优化方法的变化非常敏感。

对于它的价值,这是一个可重复的示例:

library(maxLik)

x <- test_data[, 1]

为多项式分布定义对数似然函数;我在此处加入了if语句,以防止theta < 0情况引发错误。

loglik <- function(theta, x)
    if (all(theta > 0)) sum(dmultinom(x, prob = theta, log = TRUE)) else 0

我在这里使用Nelder-Mead优化方法来找到对数似然函数的最大值。这里重要的一点是constraints参数,它以等式A theta + B = 0的形式实现约束,有关详细信息和示例,请参见?maxNM

res <- maxNM(
    loglik,
    start = rep(0.25, length(x)),
    constraints = list(
        eqA = matrix(rep(1, length(x)), ncol = length(x)),
        eqB = -1),
    x = x)

我们可以检查结果

summary(res)
--------------------------------------------
Nelder-Mead maximization
Number of iterations: 111
Return code: 0
successful convergence
Function value: -10.34576
Estimates:
      estimate     gradient
[1,] 0.2380216 -0.014219040
[2,] 0.2620168  0.012664714
[3,] 0.2450181  0.002736670
[4,] 0.2550201 -0.002369234

Constrained optimization based on SUMT
Return code: 1
penalty close to zero
1  outer iterations, barrier value 5.868967e-09
--------------------------------------------

并确认估计的总和等于1(在准确度之内)

sum(res$estimate)
#[1] 1.000077

样本数据

set.seed(1234)
test_data <- rmultinom(n = 1, size = 1000, prob = rep(1/4, 4))