From 339623ecd6a8d4a66de1eb97fd576a26ed2761ce Mon Sep 17 00:00:00 2001 From: Bob O'Hara Date: Tue, 3 Feb 2026 13:02:13 +0100 Subject: [PATCH 1/5] Correct hinge() so it doesn't create multiple copies of same feature, and changed documentation to make R CMD check happy. --- .Rbuildignore | 2 ++ .gitignore | 2 ++ DESCRIPTION | 2 +- R/hinge.R | 21 +++++++++++---------- R/predict.maxnet.R | 2 +- man/maxnet-package.Rd | 1 - man/predict.maxnet.Rd | 2 +- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index f0d5c2b..969595d 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -1,2 +1,4 @@ ^\.travis\.yml$ cran-comments.md +^.*\.Rproj$ +^\.Rproj\.user$ diff --git a/.gitignore b/.gitignore index a257aa0..117ea73 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.class *.jar *.zip +*.Rproj *~ semantic.cache html/ @@ -55,3 +56,4 @@ Network Trash Folder Temporary Items .apdisk inst/doc +.Rproj.user diff --git a/DESCRIPTION b/DESCRIPTION index 2404bf1..08362c0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -17,6 +17,6 @@ Description: Procedures to fit species distributions models from occurrence reco License: MIT + file LICENSE URL: https://github.com/mrmaxent/maxnet Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.1 +RoxygenNote: 7.3.3 LazyData: true Encoding: UTF-8 diff --git a/R/hinge.R b/R/hinge.R index e18182c..e85513e 100644 --- a/R/hinge.R +++ b/R/hinge.R @@ -33,15 +33,16 @@ #' hinge(bradypus$tmp6190_ann,nknots=10) #' categorical(bradypus$ecoreg) #' } -hinge <- -function(x, nknots=50) +hinge <- function (x, nknots = 50) { - min <- min(x) - max <- max(x) - k <- seq(min, max, length=nknots) - lh <- outer(x, utils::head(k,-1), function(w,h) hingeval(w, h, max)) - rh <- outer(x, k[-1], function(w,h) hingeval(w, min, h)) - colnames(lh) <- paste("", utils::head(k,-1), max, sep=":") - colnames(rh) <- paste("", min, k[-1], sep=":") - cbind(lh, rh) + # if(length(unique(x)) < nknots) nknots <- length(unique(x)) - 1 + Min <- min(x) + Max <- max(x) + k <- seq(Min, Max, length = nknots) + lh <- outer(x, utils::head(k, -1), function(w, h) hingeval(w, + h, Max)) + rh <- outer(x, k[-1], function(w, h) hingeval(w, Min, h)) + colnames(lh) <- paste("", utils::head(k, -1), Max, sep = ":") + colnames(rh) <- paste("", Min, k[-1], sep = ":") + cbind(lh, rh[,!colnames(rh)%in%colnames(lh)]) } diff --git a/R/predict.maxnet.R b/R/predict.maxnet.R index 470b337..fdcd0fb 100644 --- a/R/predict.maxnet.R +++ b/R/predict.maxnet.R @@ -10,7 +10,7 @@ #' @param type character, type of response required. Using \code{lp} for the linear predictor #' and \code{entropy} for the entropy of the exponential model over the background data, #' the values returned are determined by the value of \code{type}. -#' \itemize{ +#' \describe{ #' \item{"link"}{yields \code{lp}} #' \item{"exponential"}{yields \code{exp(lp)}} #' \item{"cloglog"}{yields \code{1-exp(-exp(entropy+lp))}} diff --git a/man/maxnet-package.Rd b/man/maxnet-package.Rd index 70d2976..8cd89cd 100644 --- a/man/maxnet-package.Rd +++ b/man/maxnet-package.Rd @@ -3,7 +3,6 @@ \docType{package} \name{maxnet-package} \alias{maxnet-package} -\alias{_PACKAGE} \title{Maxent over glmnet} \description{ Procedures to fit species distributions models from occurrence records and environmental variables, using 'glmnet' for model fitting. Model structure is the same as for the 'Maxent' Java package, version 3.4.0, with the same feature types and regularization options. See the 'Maxent' website \url{http://biodiversityinformatics.amnh.org/open_source/maxent} for more details. diff --git a/man/predict.maxnet.Rd b/man/predict.maxnet.Rd index 0dad803..440aee2 100644 --- a/man/predict.maxnet.Rd +++ b/man/predict.maxnet.Rd @@ -23,7 +23,7 @@ matrix, data.frame, \code{SpatRaster} or \code{stars} object.} \item{type}{character, type of response required. Using \code{lp} for the linear predictor and \code{entropy} for the entropy of the exponential model over the background data, the values returned are determined by the value of \code{type}. -\itemize{ +\describe{ \item{"link"}{yields \code{lp}} \item{"exponential"}{yields \code{exp(lp)}} \item{"cloglog"}{yields \code{1-exp(-exp(entropy+lp))}} From 251d3a40dde48c1187d0625574781ac3448c5cc9 Mon Sep 17 00:00:00 2001 From: Bob O'Hara Date: Tue, 3 Feb 2026 13:16:28 +0100 Subject: [PATCH 2/5] Added check in maxnet() to stop if a covariate only has a single value --- R/maxnet.R | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/R/maxnet.R b/R/maxnet.R index 544ad8e..fa44150 100644 --- a/R/maxnet.R +++ b/R/maxnet.R @@ -61,6 +61,10 @@ function(p, data, f=maxnet.formula(p, data), regmult=1.0, if (anyNA(data)) stop("NA values in data table. Please remove them and rerun.") if (!is.vector(p)) stop("p must be a vector.") + Nvals <- apply(data, 2, function(x) length(unique(x))) + if(any(Nvals == 1)) stop("These columns of data only have a single value: ", + paste(names(Nvals)[Nvals==1], sep=", "), + ". They should be removed") if (addsamplestobackground) { pdata <- data[p==1, , drop = FALSE] ndata <- data[p==0, , drop = FALSE] From 08b291f487cce332b1df4fc03797fca317ed756a Mon Sep 17 00:00:00 2001 From: Bob O'Hara Date: Tue, 10 Feb 2026 11:47:13 +0100 Subject: [PATCH 3/5] Add weight option to maxnet() --- R/maxnet.R | 6 ++++-- man/maxnet.Rd | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/R/maxnet.R b/R/maxnet.R index fa44150..c155ae3 100644 --- a/R/maxnet.R +++ b/R/maxnet.R @@ -26,6 +26,7 @@ #' @param m a matrix of feature values #' @param classes charcater, continuous feature classes desired, either #' "default" or any subset of "lqpht" (for example, "lh") +#' @param wt weight of absence points. Default is 100, for backwards compatibility. Can be of same length as p, to allow it to vary: note that when p=0 the weight is irrelevant. #' @param ... not used #' #' @return Maxnet returns an object of class \code{maxnet}, which is a list @@ -56,8 +57,9 @@ #' } maxnet <- function(p, data, f=maxnet.formula(p, data), regmult=1.0, - regfun=maxnet.default.regularization, addsamplestobackground=T, ...) + regfun=maxnet.default.regularization, addsamplestobackground=T, wt=100, ...) { + if(!length(wt)%in%c(1, length(p))) stop("wt should either be a scalar or the same length as p.") if (anyNA(data)) stop("NA values in data table. Please remove them and rerun.") if (!is.vector(p)) stop("p must be a vector.") @@ -75,7 +77,7 @@ function(p, data, f=maxnet.formula(p, data), regmult=1.0, } mm <- model.matrix(f, data) reg <- regfun(p,mm) * regmult - weights <- p+(1-p)*100 + weights <- p+(1-p)*wt glmnet::glmnet.control(pmin=1.0e-8, fdev=0) model <- glmnet::glmnet(x=mm, y=as.factor(p), family="binomial", standardize=F, penalty.factor=reg, lambda=10^(seq(4,0,length.out=200))*sum(reg)/length(reg)*sum(p)/sum(weights), weights=weights, ...) class(model) <- c("maxnet", class(model)) diff --git a/man/maxnet.Rd b/man/maxnet.Rd index 5ff224a..604d94f 100644 --- a/man/maxnet.Rd +++ b/man/maxnet.Rd @@ -14,6 +14,7 @@ maxnet( regmult = 1, regfun = maxnet.default.regularization, addsamplestobackground = T, + wt = 100, ... ) @@ -35,6 +36,8 @@ maxnet.formula(p, data, classes = "default") \item{addsamplestobackground}{logical, if TRUE then add to the background any presence sample that is not already there} +\item{wt}{weight of absence points. Default is 100, for backwards compatibility. Can be of same length as p, to allow it to vary: note that when p=0 the weight is irrelevant.} + \item{...}{not used} \item{m}{a matrix of feature values} From 310e6e37cdf8bebf04bc72c1d934285939405943 Mon Sep 17 00:00:00 2001 From: Bob O'Hara Date: Tue, 10 Feb 2026 12:42:39 +0100 Subject: [PATCH 4/5] Add standardize as argument to maxnet() (see https://github.com/mrmaxent/maxnet/issues/24). Updated documentation for ... Put .Rhistory in .gitignore --- .gitignore | 1 + R/maxnet.R | 12 +++++++----- man/maxnet.Rd | 7 +++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 117ea73..5f74598 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ $RECYCLE.BIN/ .TemporaryItems .Trashes .VolumeIcon.icns +.Rhistory # Directories potentially created on remote AFP share .AppleDB diff --git a/R/maxnet.R b/R/maxnet.R index c155ae3..76df71b 100644 --- a/R/maxnet.R +++ b/R/maxnet.R @@ -21,13 +21,14 @@ #' @param f formula, determines the features to be used #' @param regmult numeric, a constant to adjust regularization #' @param regfun function, computes regularization constant for each feature +#' @param standardize logical, should glmnet use internal standardization? Defaults to FALSE for backwards compatability #' @param addsamplestobackground logical, if TRUE then add to the background any #' presence sample that is not already there #' @param m a matrix of feature values -#' @param classes charcater, continuous feature classes desired, either +#' @param classes character, continuous feature classes desired, either #' "default" or any subset of "lqpht" (for example, "lh") #' @param wt weight of absence points. Default is 100, for backwards compatibility. Can be of same length as p, to allow it to vary: note that when p=0 the weight is irrelevant. -#' @param ... not used +#' @param ... other arguments passed on to glmnet #' #' @return Maxnet returns an object of class \code{maxnet}, which is a list #' consisting of a glmnet model with the following elements added: @@ -56,7 +57,7 @@ #' plot(mod, "tmp6190_ann") #' } maxnet <- -function(p, data, f=maxnet.formula(p, data), regmult=1.0, +function(p, data, f=maxnet.formula(p, data), regmult=1.0, standardize = FALSE, regfun=maxnet.default.regularization, addsamplestobackground=T, wt=100, ...) { if(!length(wt)%in%c(1, length(p))) stop("wt should either be a scalar or the same length as p.") @@ -79,7 +80,7 @@ function(p, data, f=maxnet.formula(p, data), regmult=1.0, reg <- regfun(p,mm) * regmult weights <- p+(1-p)*wt glmnet::glmnet.control(pmin=1.0e-8, fdev=0) - model <- glmnet::glmnet(x=mm, y=as.factor(p), family="binomial", standardize=F, penalty.factor=reg, lambda=10^(seq(4,0,length.out=200))*sum(reg)/length(reg)*sum(p)/sum(weights), weights=weights, ...) + model <- glmnet::glmnet(x=mm, y=as.factor(p), family="binomial", standardize=standardize, penalty.factor=reg, lambda=10^(seq(4,0,length.out=200))*sum(reg)/length(reg)*sum(p)/sum(weights), weights=weights, ...) class(model) <- c("maxnet", class(model)) if (length(model$lambda) < 200) { msg <- "Error: glmnet failed to complete regularization path. Model may be infeasible." @@ -92,7 +93,8 @@ function(p, data, f=maxnet.formula(p, data), regmult=1.0, model$alpha <- 0 rr <- predict.maxnet(model, data[p==0, , drop = FALSE], type="exponent", clamp=F) raw <- rr / sum(rr) - model$entropy <- -sum(raw * log(raw)) + if(!all(raw>0)) warning("Some fitted probabilities are not positive") + model$entropy <- -sum(raw[raw>0] * log(raw[raw>0])) model$alpha <- -log(sum(rr)) model$penalty.factor <- reg model$featuremins <- apply(mm, 2, min) diff --git a/man/maxnet.Rd b/man/maxnet.Rd index 604d94f..cba604c 100644 --- a/man/maxnet.Rd +++ b/man/maxnet.Rd @@ -12,6 +12,7 @@ maxnet( data, f = maxnet.formula(p, data), regmult = 1, + standardize = FALSE, regfun = maxnet.default.regularization, addsamplestobackground = T, wt = 100, @@ -31,6 +32,8 @@ maxnet.formula(p, data, classes = "default") \item{regmult}{numeric, a constant to adjust regularization} +\item{standardize}{logical, should glmnet use internal standardization? Defaults to FALSE for backwards compatability} + \item{regfun}{function, computes regularization constant for each feature} \item{addsamplestobackground}{logical, if TRUE then add to the background any @@ -38,11 +41,11 @@ presence sample that is not already there} \item{wt}{weight of absence points. Default is 100, for backwards compatibility. Can be of same length as p, to allow it to vary: note that when p=0 the weight is irrelevant.} -\item{...}{not used} +\item{...}{other arguments passed on to glmnet} \item{m}{a matrix of feature values} -\item{classes}{charcater, continuous feature classes desired, either +\item{classes}{character, continuous feature classes desired, either "default" or any subset of "lqpht" (for example, "lh")} } \value{ From 4463443b5facb91dfbe1a84903d6f53c13a2459d Mon Sep 17 00:00:00 2001 From: Bob O'Hara Date: Mon, 16 Mar 2026 12:01:36 +0100 Subject: [PATCH 5/5] Updated version number --- DESCRIPTION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 08362c0..1338882 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: maxnet Type: Package Title: Fitting 'Maxent' Species Distribution Models with 'glmnet' -Version: 0.1.4 -Date: 2021-07-08 +Version: 0.1.5 +Date: 2026-16-03 Author: Steven Phillips Maintainer: Steven Phillips Imports: