Created
December 21, 2014 00:58
-
-
Save zkamvar/80429412128ac6a57f3f to your computer and use it in GitHub Desktop.
Recursive function to quickly search for the parameter that maximizes a likelihood function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ============================================================================ # | |
# Quickly find the parameter that maximizes a likelihood function. | |
# | |
# This recursive function will take a range of n parameters within an interval | |
# and re-adjust the interval to border the maximum value and recursively call | |
# the function. Once the difference between the maximum value found and the | |
# previous maximum value is less than the error term, the parameter value is | |
# returned. This is faster than the brute force method as the range is reduced | |
# every time the function is recursed. | |
# | |
# PARAMETERS: | |
# LFUN vectorized likelihood function | |
# interval numeric inputs specifying the search space (inclusive) | |
# n the number of parameters to generate between the interval | |
# max set to zero. This will represent the current maximum likelihood | |
# value | |
# e an error term | |
# quiet if set to FALSE, a message with the parameter and likelihood values | |
# will be printed to screen | |
# OUTPUT: | |
# A numeric value representing the parameter that maximizes the likelihood | |
# function. | |
# ============================================================================ # | |
ml_parameter <- function(LFUN, interval = c(0, 1), n = 101, max = 0, | |
e = .Machine$double.eps^0.75, quiet = TRUE){ | |
interval <- seq(from = interval[1], to = interval[2], length = n) | |
lik <- LFUN(interval) | |
max.val <- which.max(lik) | |
max.lik <- lik[max.val] | |
max.int <- interval[max.val] | |
if (abs(log1p(max) - log1p(max.lik)) < log1p(e) && log1p(max) <= log1p(max.lik)){ | |
if (!quiet){ | |
cat("PARAMETER:\t", max.int, "\tLIKELIHOOD:\t", max.lik, "\n") | |
} | |
return(max.int) | |
} else if (log1p(max) > log1p(max.lik)) { | |
return(NULL) | |
} else if (max.val == 1){ | |
return(ml_parameter(LFUN, c(interval[1], interval[2]), n, max.lik, e, quiet)) | |
} else { | |
return(ml_parameter(LFUN, interval[max.val + c(-1, 1)], n, max.lik, e, quiet)) | |
} | |
} | |
# ============================================================================ # | |
# # Uncomment this to run an example from the R package adegenet: | |
# | |
# library(adegenet) | |
# data(microbov) | |
# sal <- seppop(microbov)$Salers | |
# Fsal <- inbreeding(sal, res.type = "function") | |
# Fest <- sapply(Fsal, ml_parameter) | |
# plot(Fest) | |
# ============================================================================ # | |
# ============================================================================ # | |
# Benchmarking | |
# | |
# This benchmark is based on the function below, which will find the parameter | |
# that maximizes the likelihood function among n parameters. | |
# ============================================================================ # | |
seq_max <- function(LFUN, n = 1001, interval = c(0, 1)){ | |
ran <- seq(from = interval[1], to = interval[2], length= n) | |
ran[which.max(LFUN(ran))] | |
} | |
# ============================================================================ # | |
# # Uncomment this section to perform the benchmark | |
# | |
# F37 <- Fsal[[37]] ## Maximum inbreeding coefficient | |
# (mlp.res <- ml_parameter(F37)) | |
# (sm.res <- seq_max(F37)) # Note, this is with 1001 parameters | |
# (p1k <- F37(c(mlp.res, sm.res))) | |
# which.max(p1k) | |
# diff(p1k) | |
# sm.res <- seq_max(F37, n = 10001) # increasing the number of iterations | |
# (p10k <- F37(c(mlp.res, sm.res))) | |
# which.max(p10k) | |
# diff(p10k) | |
# library(microbenchmark) | |
# library(ggplot2) | |
# (mb.res <- microbenchmark(ml_parameter(F37), seq_max(F37))) | |
# autoplot(mb.res) | |
# ============================================================================ # |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note: this function bows before the stats function,
optimize
, which is faster and more rigorous.