補充資料——自己實現極大似然估計(最大似然估計)MLE


這篇文章給了我一個啟發,我們可以自己用已知分布的密度函數進行組合,然后構建一個新的密度函數啦,然后用極大似然估計MLE進行估計。

代碼和結果演示
代碼:
   
   
   
           
  1. #取出MASS包這中的數據
  2. data(geyser,package="MASS")
  3. head(geyser)
  4. attach(geyser)
  5. par(bg='lemonchiffon')
  6. hist(waiting,freq=F,col="lightcoral")
  7. #freq=F要加上,否則就無法添加線了
  8. lines(density(waiting),lwd=2,col="cadetblue4")
  9. #根據圖像,我們認為其在前后分別是兩個正態分布函數的組合
  10. #定義 log‐likelihood 函數
  11. LL<-function(params,data){
  12. #參數"params"是一個向量,
  13. #依次包含了五個參數: p,mu1,sigma1,mu2,sigma2.
  14. #參數"data",是觀測數據。
  15. t1<-dnorm(data,params[2],params[3])
  16. t2<-dnorm(data,params[4],params[5])
  17. #f是概率密度函數
  18. f<-params[1]*t1+(1-params[1])*t2
  19. #混合密度函數
  20. ll<-sum(log(f))
  21. #log‐likelihood 函數
  22. return(-ll)
  23. #nlminb()函數是最小化一個函數的值,
  24. #但我們是要最大化 log‐likeilhood 函數
  25. #所以需要在“ ll”前加個“ ‐”號。
  26. }
  27. #估計函數####optim####
  28. # debugonce(nlminb)
  29. geyser.res<-nlminb(c(0.5,50,10,80,10),LL,data=waiting,
  30. lower=c(0.0001,-Inf,0.0001,
  31. -Inf,0.0001),
  32. upper=c(0.9999,Inf,Inf,Inf,Inf))
  33. #初始值為 p=0.5,mu1=50,sigma1=10,mu2=80,sigma2=10
  34. #初始值也會被傳遞給LL
  35. #LL 是被最小化的函數。
  36. #data 是估計用的數據(傳遞給我們的LL)
  37. #lower 和 upper 分別指定參數的上界和下界。
  38. #查看擬合的參數
  39. geyser.res$par
  40. #擬合的效果
  41. #解釋變量
  42. X<-seq(40,120,length=100)
  43. #讀出估計的參數
  44. p<-geyser.res$par[1]
  45. mu1<-geyser.res$par[2]
  46. sig1<-geyser.res$par[3]
  47. mu2<-geyser.res$par[4]
  48. sig2<-geyser.res$par[5]
  49. #將估計的參數函數代入原密度函數。
  50. f<-p*dnorm(X,mu1,sig1)+(1-p)*dnorm(X,mu2,sig2)
  51. #作出數據的直方圖
  52. hist(waiting,probability=T,col='lightpink3',
  53. ylab="Density",ylim=c(0,0.04),
  54. xlab="Eruption waiting times"
  55. )
  56. #畫出擬合的曲線
  57. lines(X,f,col='lightskyblue3',lwd=2)
  58. detach(geyser)

調試的說明
nlminb函數:
nlminb(c(0.5,50,10,80,10),LL,data=waiting,
                   lower=c(0.0001,-Inf,0.0001,
                           -Inf,0.0001),
                   upper=c(0.9999,Inf,Inf,Inf,Inf))
   
   
   
           
  1. function (start, objective, gradient = NULL, hessian = NULL,
  2. ..., scale = 1, control = list(), lower = -Inf, upper = Inf)
  3. {
  4. par <- setNames(as.double(start), names(start))
  5. n <- length(par)
  6. iv <- integer(78 + 3 * n)
  7. v <- double(130 + (n * (n + 27))/2)
  8. .Call(C_port_ivset, 2, iv, v)
  9. if (length(control)) {
  10. nms <- names(control)
  11. if (!is.list(control) || is.null(nms))
  12. stop("'control' argument must be a named list")
  13. pos <- pmatch(nms, names(port_cpos))
  14. if (any(nap <- is.na(pos))) {
  15. warning(sprintf(ngettext(length(nap), "unrecognized control element named %s ignored",
  16. "unrecognized control elements named %s ignored"),
  17. paste(sQuote(nms[nap]), collapse = ", ")), domain = NA)
  18. pos <- pos[!nap]
  19. control <- control[!nap]
  20. }
  21. ivpars <- pos <= 4
  22. vpars <- !ivpars
  23. if (any(ivpars))
  24. iv[port_cpos[pos[ivpars]]] <- as.integer(unlist(control[ivpars]))
  25. if (any(vpars))
  26. v[port_cpos[pos[vpars]]] <- as.double(unlist(control[vpars]))
  27. }
  28. obj <- quote(objective(.par, ...))

  29. rho <- new.env(parent = environment())

  30. assign(".par", par, envir = rho)
  31. grad <- hess <- low <- upp <- NULL
  32. if (!is.null(gradient)) {
  33. grad <- quote(gradient(.par, ...))
  34. if (!is.null(hessian)) {
  35. if (is.logical(hessian))
  36. stop("logical 'hessian' argument not allowed. See documentation.")
  37. hess <- quote(hessian(.par, ...))
  38. }
  39. }
  40. if (any(lower != -Inf) || any(upper != Inf)) {
  41. low <- rep_len(as.double(lower), length(par))
  42. upp <- rep_len(as.double(upper), length(par))
  43. }
  44. else low <- upp <- numeric()
  45. .Call(C_port_nlminb, obj, grad, hess, rho, low, upp, d = rep_len(as.double(scale),
  46. length(par)), iv, v)
  47. iv1 <- iv[1L]
  48. list(par = get(".par", envir = rho), objective = v[10L],
  49. convergence = (if (iv1 %in% 3L:6L) 0L else 1L), iterations = iv[31L],
  50. evaluations = c(`function` = iv[6L], gradient = iv[30L]),
  51. message = if (19 <= iv1 && iv1 <= 43) {
  52. if (any(B <- iv1 == port_cpos)) sprintf("'control' component '%s' = %g, is out of range",
  53. names(port_cpos)[B], v[iv1]) else sprintf("V[IV[1]] = V[%d] = %g is out of range (see PORT docu.)",
  54. iv1, v[iv1])
  55. } else port_msg(iv1))
  56. }
par最先獲得了初始值
obj <- quote(objective(.par, ...))
讓obj表示一個名為 objective,接受形參.par和...的函數,即我們傳入的對數似然函數
rho <- new.env(parent = environment())
創建新環境
assign(".par", par, envir = rho)
par賦給 rho環境中的 .par變量
.Call(C_port_nlminb, obj, grad, hess, 
        rho, low, upp, d = rep_len(as.double(scale),  length(par)), iv, v)
C_port_nlminb在名為stats.dll的包里,我用reflector和VS都沒能看到什么東西,唉,最關鍵的東西是缺失的。
此時rho包含了參數的初始值,而obj接受.par和多出來的data,即參數初始值和數據。
nlminb 函數的幫助文檔里提到:
...
Further arguments to be supplied to objective.
即在這里是傳遞給對數似然函數的更多參數,這里是data,之所以LL的第一個參數不需要傳入是因為我們在源碼看到其是.par,也可以在幫助文檔看到:
objective
Function to be minimized. Must return a scalar value. The first argument to objective is the vector of parameters to be optimized, whose initial values are supplied through start(start 參數). Further arguments (fixed during the course of the optimization) to objective may be specified as well (see ...(參數)).

---------------------------------------
參考:
原文檔:




附件列表

     


    免責聲明!

    本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



     
    粵ICP備18138465號   © 2018-2025 CODEPRJ.COM