/*
Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
This file is part of CamCOPS.
CamCOPS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CamCOPS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
// #define STATSFUNC_OFFER_AIC
#include "maths/include_eigen_dense.h" // IWYU pragma: keep
class LinkFunctionFamily;
namespace statsfunc {
// ============================================================================
// Eigen statistical calculations
// ============================================================================
// Calculates the (sample) variance of an Eigen array.
template<typename Derived> double variance(const Eigen::ArrayBase<Derived>& a)
{
double n = a.size();
double mean = a.mean();
double ss = (a - mean).square().sum();
// ... sum of squared deviations from the mean
return ss / (n - 1);
}
// Calculates the (sample) variance of an Eigen matrix.
template<typename Derived> double variance(const Eigen::MatrixBase<Derived>& m)
{
// For elementwise operations, we need an Array, not a Matrix.
return variance(m.array());
}
// ============================================================================
// Elementary functions
// ============================================================================
// Returns x unmodified.
double identity(double x);
// Returns x unmodified.
Eigen::ArrayXXd identityArray(const Eigen::ArrayXXd& x);
// Returns 1. (Derivative of the identity function.)
double one(double x);
// Returns an array of ones of the same size as x.
Eigen::ArrayXXd oneArray(const Eigen::ArrayXXd& x);
// Returns the natural log of x, where x is an array.
Eigen::ArrayXXd logArray(const Eigen::ArrayXXd& x);
// Returns e^x, where x is an array.
Eigen::ArrayXXd expArray(const Eigen::ArrayXXd& x);
// Returns the logistic function of x.
// = 1 / (1 + exp(-x))
// = exp(x) / (1 + exp(x))
// - The core logistic function, a sigmoid.
// - Transforms logit -> probability; inverse of logit()
double logistic(double x);
// Applies the logistic function to x, an array.
Eigen::ArrayXXd logisticArray(const Eigen::ArrayXXd& x);
// Returns logistic(intercept + slope * x).
double logisticInterceptSlope(double x, double intercept, double slope);
// Generalized logistic function with k steepness, x0 midpoint.
// https://en.wikipedia.org/wiki/Logistic_function
// = logistic(k * (x - x0));
double logisticX0K(double x, double x0, double k);
// Derivative of logistic function
// = exp(x) / (1 + exp(x))^2
// = f(x)(1 - f(x)) where f(x) = logistic(x) = 1 / (1 + exp(-x))
// https://en.wikipedia.org/wiki/Logistic_function#Derivative
double derivativeOfLogistic(double x);
// Derivative of logistic function, applied to an array.
Eigen::ArrayXXd derivativeOfLogisticArray(const Eigen::ArrayXXd& x);
// Logit function
// = inverse of logistic function
// = log(p / (1 - p))
// - Transforms probability -> logit; inverse of logistic()
// - https://en.wikipedia.org/wiki/Logit
// - Uses natural logs (std::log).
double logit(double p);
// Logit function, applied to an array.
Eigen::ArrayXXd logitArray(const Eigen::ArrayXXd& p);
// Returns true
bool alwaysTrue(const Eigen::ArrayXd& x);
// Are all of the array elements integer (or within threshold of an integer)?
bool allInteger(const Eigen::ArrayXd& x, double threshold = 0.001);
// ============================================================================
// Functions for specific GLM families
// ============================================================================
// ----------------------------------------------------------------------------
// binomial
// ----------------------------------------------------------------------------
// Binomial variance function.
// - R: binomial()$variance
// - https://en.wikipedia.org/wiki/Variance_function#Example_.E2.80.93_Bernoulli
Eigen::ArrayXXd binomialVariance(const Eigen::ArrayXXd& x);
// R: binomial_dev_resids()
Eigen::ArrayXd binomialDevResids(
const Eigen::ArrayXd& y, const Eigen::ArrayXd& mu, const Eigen::ArrayXd& wt
);
// R: binomial()$validmu
bool binomialValidMu(const Eigen::ArrayXd& mu);
// R: binomial()$initialize
// Returns: OK?
bool binomialInitialize(
QStringList& errors,
const LinkFunctionFamily& family,
Eigen::ArrayXd& y,
Eigen::ArrayXd& n,
Eigen::ArrayXd& m,
Eigen::ArrayXd& weights,
Eigen::ArrayXd& start,
Eigen::ArrayXd& etastart,
Eigen::ArrayXd& mustart
);
#ifdef STATSFUNC_OFFER_AIC
// As per R's dbinom()
double dbinom(double x, int n, double p, bool log = false);
// As per R's dbinom()
Eigen::ArrayXd dbinom(
const Eigen::ArrayXd& x,
const Eigen::ArrayXi& n,
const Eigen::ArrayXd& p,
bool log = false
);
// R: binomial()$aic
double binomialAIC(
const Eigen::ArrayXd& y,
const Eigen::ArrayXd& n,
const Eigen::ArrayXd& mu,
const Eigen::ArrayXd& wt,
double dev
);
#endif
// ----------------------------------------------------------------------------
// gaussian
// ----------------------------------------------------------------------------
// R: gaussian()$dev.resids
Eigen::ArrayXd gaussianDevResids(
const Eigen::ArrayXd& y, const Eigen::ArrayXd& mu, const Eigen::ArrayXd& wt
);
// R: gaussian()$initialize
// Returns: OK?
bool gaussianInitialize(
QStringList& errors,
const LinkFunctionFamily& family,
Eigen::ArrayXd& y,
Eigen::ArrayXd& n,
Eigen::ArrayXd& m,
Eigen::ArrayXd& weights,
Eigen::ArrayXd& start,
Eigen::ArrayXd& etastart,
Eigen::ArrayXd& mustart
);
#ifdef STATSFUNC_OFFER_AIC
// R: gaussian()$aic
double gaussianAIC(
const Eigen::ArrayXd& y,
const Eigen::ArrayXd& n,
const Eigen::ArrayXd& mu,
const Eigen::ArrayXd& wt,
double dev
);
#endif
// ----------------------------------------------------------------------------
// poisson
// ----------------------------------------------------------------------------
// R: poisson()$validmu
bool poissonValidMu(const Eigen::ArrayXd& mu);
// R: poisson()$dev.resids
Eigen::ArrayXd poissonDevResids(
const Eigen::ArrayXd& y, const Eigen::ArrayXd& mu, const Eigen::ArrayXd& wt
);
// R: poisson()$initialize
// Returns: OK?
bool poissonInitialize(
QStringList& errors,
const LinkFunctionFamily& family,
Eigen::ArrayXd& y,
Eigen::ArrayXd& n,
Eigen::ArrayXd& m,
Eigen::ArrayXd& weights,
Eigen::ArrayXd& start,
Eigen::ArrayXd& etastart,
Eigen::ArrayXd& mustart
);
#ifdef STATSFUNC_OFFER_AIC
// R: poisson()$aic
double poissonAIC(
const Eigen::ArrayXd& y,
const Eigen::ArrayXd& n,
const Eigen::ArrayXd& mu,
const Eigen::ArrayXd& wt,
double dev
); // NOT YET IMPLEMENTED
#endif
// ============================================================================
// Solving
// ============================================================================
// Singular value decomposition (SVD) solving.
// Solves Ax = b [or b = Ax + e], for x, minimizing e (in a least-squares
// sense).
Eigen::VectorXd svdSolve(const Eigen::MatrixXd& A, const Eigen::VectorXd& b);
// ============================================================================
// GLM support
// ============================================================================
// ... see glm.h
/*
Eigen::Array<Eigen::Index, Eigen::Dynamic, 1> svdsubsel(
const Eigen::MatrixXd& A, int k = -1);
*/
} // namespace statsfunc