Nothing
#' Extract meaningful information from the von Mises-Fisher mixture model
#'
#' Given a mixture of von Mises-Fisher distributions, this function computes
#' several related quantities of the data on the unit hypersphere with respect
#' to the specified model.
#'
#' @param data an \eqn{(n\times d)} data matrix.
#' @param means an \eqn{(k\times d)} matrix of means.
#' @param concentrations a vector of length \eqn{k} of concentration parameters.
#' @param weights a vector of length \eqn{k} of mixing weights.
#'
#' @return a named list containing \describe{
#' \item{densities}{a vector of length \eqn{n} of the densities of the data points.}
#' \item{clustering}{a vector of length \eqn{n} of the hard clustering results.}
#' \item{loglkd}{the log-likelihood of the data.}
#' \item{AIC}{the Akaike information criterion.}
#' \item{BIC}{the Bayesian information criterion.}
#' }
#'
#' @export
movMF_info <- function(data, means, concentrations, weights){
###############################################
# Preprocessing
# data
if (!is.matrix(data)){
my_data = cpp_WL_normalise(as.matrix(data))
} else {
my_data = cpp_WL_normalise(data)
}
# means
if (!is.matrix(means)){
my_means = cpp_WL_normalise(as.matrix(means))
} else {
my_means = cpp_WL_normalise(means)
}
# concentrations
my_concentrations = as.vector(concentrations)
if (length(my_concentrations)!=base::nrow(my_means)){
stop("* movMF_info : cardinalities of the means and concentrations do not match.")
}
# weights
if ((length(weights)==0)&&(is.null(weights))){
my_weights = rep(1/length(my_concentrations), length(my_concentrations))
} else {
my_weights = as.vector(weights)
my_weights = my_weights/base::sum(my_weights)
}
if (any(my_weights < .Machine$double.eps)||(length(my_weights)!=length(my_concentrations))){
stop("* movMF_info : invalid 'weights'. Please see the documentation.")
}
###############################################
# BASIC COMPUTATION
par_n = base::nrow(my_data)
par_p = base::ncol(my_data)
par_k = base::length(my_weights)
membership <- array(0,c(par_n, par_k))
for (k in 1:par_k){
membership[,k] <- aux_vmf_density(my_data, my_means[k,], my_concentrations[k])*my_weights[k]
}
###############################################
# ADVANCED
# density (n,) vector
out_densities = base::rowSums(membership)
# hard clustering results
out_cluster = rep(0, par_n)
for (i in 1:par_n){
tmp_clust <- as.vector(membership[i,])
tmp_clust <- tmp_clust/base::sum(tmp_clust)
out_cluster[i] <- which.max(tmp_clust)
}
# log-likelihood
out_loglkd <- base::sum(base::log(out_densities))
# information criteria
df <- (par_k - 1) + par_k*((par_p-1)+1)
out_aic <- -2*out_loglkd + 2*df
out_bic <- -2*out_loglkd + base::log(par_n)*df
###############################################
# RETURN
output = list()
output$densities = out_densities
output$clustering = out_cluster
output$loglkd <- out_loglkd
output$AIC <- out_aic
output$BIC <- out_bic
return(output)
}
# auxiliary functions -----------------------------------------------------
#' @keywords internal
#' @noRd
aux_vmf_density <- function(x, mu, kappa){
# x : (n x d) data matrix
# mu : (d,) mean vector
# kappa : >0 concentration parameter
# initialization
d <- base::ncol(x)
# normalizing constant
log_c_p_kappa <- (d/2 - 1) * log(kappa) - (d/2) * log(2 * pi) - log(base::besselI(kappa, nu = d/2 - 1, expon.scaled = TRUE)) - kappa
c_p_kappa <- exp(log_c_p_kappa)
# iterate
densities = rep(0, base::nrow(x))
for (i in 1:base::nrow(x)){
densities[i] <- base::exp(kappa*base::sum(as.vector(x[i,])*mu))*c_p_kappa
}
return(densities)
}
# # simple example
# # data matrix normalized
# X = as.matrix(iris[,2:4])
# X = as.matrix(scale(X, center=TRUE, scale=FALSE))
# X = X/sqrt(rowSums(X^2))
#
# # fit the model with movMF package
# out_movMF <- movMF::movMF(X, 3)
# clust_movMF <- predict(out_movMF, X)
#
# # use my function
# fit_weights <- out_movMF$alpha
# fit_means <- out_movMF$theta/sqrt(rowSums(out_movMF$theta^2))
# fit_concentrations <- sqrt(rowSums(out_movMF$theta^2))
# clust_mine <- movMF_info(X, fit_means, fit_concentrations, fit_weights)$clustering
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.