UNPKG

ts-math

Version:

A collection of math functions and packages written in Typescript

372 lines 11.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.polynomialRegression = exports.qqRegression = exports.linearRegression = exports.indexOf = exports.range = exports.round = exports.quantile = exports.normalCdf = exports.normalInv = exports.erfcinv = exports.erfc = exports.erf = exports.kurtosis = exports.skew = exports.cov = exports.corr = exports.stdev = exports.mean = exports.sum = exports.sqr = void 0; const numeric_1 = __importDefault(require("numeric")); const { sqrt, log, exp, cos, PI, pow, SQRT2, floor } = Math; const sqr = (x) => x * x; exports.sqr = sqr; // \operatorname{sum}(x)=\sum{x} function sum(xs) { let n = xs.length; let sx = 0; for (let i = 0; i < n; i++) { sx += xs[i]; } return sx; } exports.sum = sum; // \operatorname{mean}(x)=\frac{\sum{x}}{n} function mean(xs) { let n = xs.length; return sum(xs) / n; } exports.mean = mean; /** * Calculates the standard deviation of samples in the input array * ``` * \operatorname{stdev}(x)=\sqrt{\frac{\sum{x^2}-\frac{\sum{x}}{n}}{n-1}} * ``` */ function stdev(xs) { var n = xs.length; var sx = 0; var sx2 = 0; for (let i = 0; i < n; i++) { let x = xs[i]; sx += x; sx2 += exports.sqr(x); } return sqrt((sx2 - exports.sqr(sx) / n) / (n - 1)); } exports.stdev = stdev; /** * The corr function returns the correlation coefficient of two * ``` * \operatorname{corr}(x,y)=\frac{n\sum{xy}-\sum{x}\sum{y}}{\sqrt{(n\sum{x^2}-(\sum{x})^2)(n\sum{y^2}-(\sum{y})^2)}} * ``` */ function corr(xs, ys) { var n = xs.length; var sx = 0; var sy = 0; var sxy = 0; var sx2 = 0; var sy2 = 0; for (let i = 0; i < n; i++) { let x = xs[i]; let y = ys[i]; sx += x; sy += y; sxy += x * y; sx2 += exports.sqr(x); sy2 += exports.sqr(y); } return (n * sxy - sx * sy) / sqrt((n * sx2 - exports.sqr(sx)) * (n * sy2 - exports.sqr(sy))); } exports.corr = corr; /** * The cov function calculates the covariance between the two arrays. * ``` * \operatorname{cov}(x,y)=\frac{\sum{xy}-\frac{\sum{x}\sum{y}}{n}}{n-1} * ``` */ function cov(xs, ys) { var n = xs.length; var sx = 0; var sy = 0; var sxy = 0; for (let i = 0; i < n; i++) { let x = xs[i]; let y = ys[i]; sx += x; sy += y; sxy += x * y; } return (sxy - (sx * sy) / n) / (n - 1); } exports.cov = cov; /** * In probability theory and statistics, skewness is a measure of the asymmetry of the probability distribution of a real-valued random * variable about its mean. */ function skew(xs) { var n = xs.length; var sx = 0; var sx2 = 0; var sx3 = 0; for (let i = 0; i < n; i++) { let x = xs[i]; let x2 = exports.sqr(x); sx += x; sx2 += x2; sx3 += x * x2; } var n2 = exports.sqr(n); var stdev = sqrt((sx2 - pow(sx, 2) / n) / (n - 1)); return ((n / (n - 1) / (n - 2)) * (sx3 - (3 / n) * sx * sx2 + (2 / n2) * pow(sx, 3))) / pow(stdev, 3); } exports.skew = skew; /** * In probability theory and statistics, kurtosis (from Greek: κυρτός, kyrtos or kurtos, meaning "curved, arching") is a measure of the * "tailedness" of the probability distribution of a real-valued random variable. */ function kurtosis(xs) { var n = xs.length; var sx = 0; var sx2 = 0; var sx3 = 0; var sx4 = 0; for (let i = 0; i < n; i++) { let x = xs[i]; sx += x; sx2 += exports.sqr(x); sx3 += pow(x, 3); sx4 += pow(x, 4); } var n2 = pow(n, 2); var n3 = pow(n, 3); var stdev = sqrt((sx2 - exports.sqr(sx) / n) / (n - 1)); var m4 = (1 / n) * (sx4 - (4 / n) * sx * sx3 + (6 / n2) * exports.sqr(sx) * sx2 - (3 / n3) * pow(sx, 4)); return ((n2 * (n + 1) * m4) / pow(stdev, 4) - 3 * pow(n - 1, 3)) / (n - 1) / (n - 2) / (n - 3); } exports.kurtosis = kurtosis; /** * erf is the "error function" encountered in integrating the normal distribution (which is a normalized form of the Gaussian function). * It is an entire function defined by * ``` * \operatorname{erf}(z) = \frac{2}{\sqrt{\pi}}\int_{0}^z e^{-t^2}dt * ``` */ function erf(z) { var cof = [ -1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2, -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4, 4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6, 1.30365583558e-6, 1.5626441722e-8, -8.5238095915e-8, 6.529054439e-9, 5.059343495e-9, -9.91364156e-10, -2.27365122e-10, 9.6467911e-11, 2.394038e-12, -6.886027e-12, 8.94487e-13, 3.13092e-13, -1.12708e-13, 3.81e-16, 7.106e-15, -1.523e-15, -9.4e-17, 1.21e-16, -2.8e-17, ]; var j = cof.length - 1; var isneg = false; var d = 0; var dd = 0; var t, ty, tmp, res; if (z < 0) { z = -z; isneg = true; } t = 2 / (2 + z); ty = 4 * t - 2; for (; j > 0; j--) { tmp = d; d = ty * d - dd + cof[j]; dd = tmp; } res = t * exp(-z * z + 0.5 * (cof[0] + ty * d) - dd); return isneg ? res - 1 : 1 - res; } exports.erf = erf; /** * The complementary error function */ function erfc(x) { return 1 - erf(x); } exports.erfc = erfc; /** * Inverse complementary error function */ function erfcinv(p) { var j = 0; var x, err, t, pp; if (p >= 2) return -100; if (p <= 0) return 100; pp = p < 1 ? p : 2 - p; t = sqrt(-2 * log(pp / 2)); x = -0.70711 * ((2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t); for (; j < 2; j++) { err = erfc(x) - pp; x += err / (1.12837916709551257 * exp(-x * x) - x * err); } return p < 1 ? x : -x; } exports.erfcinv = erfcinv; /** * Normal inverse cumulative distribution function * @param {Number} p Probability * @param {Number} mu Mean * @param {Number} sigma Standard deviation */ function normalInv(p, mu, sigma) { return -SQRT2 * sigma * erfcinv(2 * p) + mu; } exports.normalInv = normalInv; /** * Normal cumulative distribution function * @param {*} x Value * @param {*} mu Mean * @param {*} sigma Standard deviation */ function normalCdf(x, mu, sigma) { return 0.5 * erfc(-(x - mu) / sigma / SQRT2); } exports.normalCdf = normalCdf; /** * Function that returns the q-th quantile of a dataset (same as numpy.quantile in Python) */ function quantile(xs, q) { var index, i; xs.sort((a, b) => a - b); //sort smallest to largest index = q * (xs.length - 1); i = floor(index); if (i === index) return xs[index]; return Number((index - i) * xs[i + 1] + (i + 1 - index) * xs[i]); } exports.quantile = quantile; /** * Rounds with decimals. It should round away from zero, therefore it rounds absolute amount. It also adds a small amount to avoid * midpoint rounding issues, like 0.4999999999 should round to 1 */ function round(x, decimals) { var p = pow(10, decimals); return (Math.sign(x) * Math.round(p * Math.abs(x) + 0.01 / p)) / p; } exports.round = round; /** * Generates an array of numbers. Values are set to 0 up to n-1, incrementing by 1. * @param n The numbers of array items. * @returns array of numbers */ function range(n) { const res = new Array(n); for (let i = 0; i < n; i++) { res[i] = i; } return res; } exports.range = range; /** * Returns the index of the highest element that is lower or equal to t. The input array must be ordered in ascending order. * @param t * @param vs * @returns */ function indexOf(t, vs) { let i = -1; let n = vs.length; if (n === 0) return -1; else if (t < vs[0]) return -1; else if (t >= vs[n - 1]) return n - 1; if (n > 40) { //Binary search if >40 (otherwise it's no gain using it) let hi = n - 1; let low = 0; if (t >= vs[hi]) return hi; while (hi > low + 1) { i = floor((hi + low) / 2); if (t >= vs[i]) { low = i; } else { hi = i; i = low; } } return i; } else { //Incremental search i = 1; while (t >= vs[i] && i < n - 1) { i++; } return i - 1; } } exports.indexOf = indexOf; /** * Linear regression of xs-values against ys-values. Weighted by ws-values (if included). * @param xs * @param ys * @param ws * @returns */ function linearRegression(xs, ys, ws = null) { let swx = 0.0; let swx2 = 0.0; let sw = 0.0; let swy = 0.0; let swxy = 0.0; const n = xs.length; for (let i = 0; i < n; i++) { const x = xs[i]; const w = ws ? ws[i] : 1; const y = ys[i]; const xw = x * w; swx += xw; swx2 += xw * x; sw += w; swy += w * y; swxy += xw * y; } const a = swx2 * sw - exports.sqr(swx); const k = (swxy * sw - swx * swy) / a; const b = (swx2 * swy - swxy * swx) / a; let error = 0; for (let i = 0; i < n; i++) { error += exports.sqr(k * xs[i] + b - ys[i]) * (ws ? ws[i] : 1); } error /= sw; return { k, b, error }; } exports.linearRegression = linearRegression; /** * Assumes the vs-values are normally distributed, adds them to a QQ-plot and estimates the mean, stdev by linear regression in the plot. * The values in the QQ-plot can be centrally weighted (useful if data can contain anomalies or non-normally extreme jumps). * @param vs * @param centrallyWeighted true or false * @returns */ function qqRegression(vs, centrallyWeighted = false) { const n = vs.length; vs.sort((d1, d2) => d1 - d2); const xs = new Array(n); const ws = centrallyWeighted ? new Array(n) : null; for (let i = 0; i < n; i++) { let u = (i + 0.5) / n; xs[i] = normalInv(u, 0, 1); if (centrallyWeighted) { ws[i] = (1 + cos(2 * PI * (u - 0.5))) / 2; } } const { k, b, error } = linearRegression(xs, vs, ws); return { stdev: k, mean: b, error }; } exports.qqRegression = qqRegression; /** * Polynomial regression. Estimates the coefficients of the polynomial expression the fits the xs and ys-values. Weighted by ws-values (if included). * @param xs x-values * @param ys y-values * @param ws weights * @returns coefficients array */ function polynomialRegression(xs, ys, ws = null, n) { const xxs = xs.map((d) => [...Array(n + 1)].map((e, i) => pow(d, n - i))); let wxs = ws ? xxs.map((d, i) => d.map((e) => ws[i] * e)) : xxs; const xsT = numeric_1.default.transpose(xxs); const xsTxs = numeric_1.default.dot(xsT, wxs); const xsTys = numeric_1.default.dot(xsT, ws ? ys.map((d, i) => d * ws[i]) : ys); const res = numeric_1.default.solve(xsTxs, xsTys); return res; } exports.polynomialRegression = polynomialRegression; //# sourceMappingURL=Math.js.map