name:
dist/Formulas/Range.js
-rw-r--r--
5871
1"use strict";
2exports.__esModule = true;
3var ArgsChecker_1 = require("../Utilities/ArgsChecker");
4var Filter_1 = require("../Utilities/Filter");
5var TypeConverter_1 = require("../Utilities/TypeConverter");
6var Errors_1 = require("../Errors");
7var MathHelpers_1 = require("../Utilities/MathHelpers");
8/**
9 * Calculates the frequency distribution of a range into specified classes or "bins".
10 * @param range - to get frequency for.
11 * @param bins - or classes.
12 * @returns {Array<number>}
13 * @constructor
14 * TODO: Returns ColumnArray (values stacked in Y-direction)
15 */
16var FREQUENCY = function (range, bins) {
17 ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "FREQUENCY");
18 if (!Array.isArray(bins)) {
19 bins = [bins];
20 }
21 if (!Array.isArray(range)) {
22 range = [range];
23 }
24 bins = Filter_1.Filter.flattenAndThrow(bins).map(function (value) {
25 return TypeConverter_1.TypeConverter.firstValueAsNumber(value);
26 }).sort(function (a, b) {
27 return a - b;
28 });
29 range = Filter_1.Filter.flattenAndThrow(range).map(function (value) {
30 return TypeConverter_1.TypeConverter.firstValueAsNumber(value);
31 }).sort(function (a, b) {
32 return a - b;
33 });
34 var n = range.length;
35 var b = bins.length;
36 var r = [];
37 for (var i = 0; i <= b; i++) {
38 r[i] = 0;
39 for (var j = 0; j < n; j++) {
40 if (i === 0) {
41 if (range[j] <= bins[0]) {
42 r[0] += 1;
43 }
44 }
45 else if (i < b) {
46 if (range[j] > bins[i - 1] && range[j] <= bins[i]) {
47 r[i] += 1;
48 }
49 }
50 else if (i === b) {
51 if (range[j] > bins[b - 1]) {
52 r[b] += 1;
53 }
54 }
55 }
56 }
57 return r;
58};
59exports.FREQUENCY = FREQUENCY;
60/**
61 * Given partial data with exponential growth, fits and ideal exponential growth trend, and predicts future values. For
62 * more information see: https://xkcd.com/1102/
63 * @param knownY - The range or array containing the dependent, y, values that are known, and will be used to fit an
64 * ideal exponential growth curve.
65 * @param knownX - OPTIONAL - The range or values of the independent variables that correspond to knownY.
66 * @param newX - OPTIONAL - The range, values, or data-points to return the y-values on the ideal curve fit.
67 * @param shouldUseConstant - OPTIONAL - True by default. Given an exponential function y = b*m^x, should this function
68 * calculate b?
69 * @returns {Array}
70 * @constructor
71 * TODO: Returns RowArray (values stacked in X-direction)
72 */
73var GROWTH = function (knownY, knownX, newX, shouldUseConstant) {
74 ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 4, "GROWTH");
75 // Credits: Ilmari Karonen, FormulaJs (https://github.com/sutoiku/formula.js/)
76 knownY = Filter_1.Filter.flattenAndThrow(knownY).map(function (value) {
77 if (typeof value !== "number") {
78 throw new Errors_1.ValueError("Function GROWTH parameter 1 expects number values. But '" + value + "' is " + (typeof value)
79 + " and cannot be coerced to a number.");
80 }
81 return value;
82 });
83 // Default values for optional parameters:
84 if (arguments.length < 2) {
85 knownX = [];
86 for (var i = 1; i <= knownY.length; i++) {
87 knownX.push(i);
88 }
89 }
90 if (arguments.length < 3) {
91 newX = [];
92 for (var i = 1; i <= knownY.length; i++) {
93 newX.push(i);
94 }
95 }
96 if (arguments.length < 4) {
97 shouldUseConstant = true || shouldUseConstant;
98 }
99 // Calculate sums over the data:
100 var n = knownY.length;
101 var avg_x = 0;
102 var avg_y = 0;
103 var avg_xy = 0;
104 var avg_xx = 0;
105 for (var i = 0; i < n; i++) {
106 var x = knownX[i];
107 var y = Math.log(knownY[i]);
108 avg_x += x;
109 avg_y += y;
110 avg_xy += x * y;
111 avg_xx += x * x;
112 }
113 avg_x /= n;
114 avg_y /= n;
115 avg_xy /= n;
116 avg_xx /= n;
117 // Compute linear regression coefficients:
118 var beta;
119 var alpha;
120 if (shouldUseConstant) {
121 beta = (avg_xy - avg_x * avg_y) / (avg_xx - avg_x * avg_x);
122 alpha = avg_y - beta * avg_x;
123 }
124 else {
125 beta = avg_xy / avg_xx;
126 alpha = 0;
127 }
128 // Compute and return result array:
129 var new_y = [];
130 for (var i = 0; i < newX.length; i++) {
131 new_y.push(Math.exp(alpha + beta * newX[i]));
132 }
133 return new_y;
134};
135exports.GROWTH = GROWTH;
136/**
137 * Returns the parameters of a linear trend.
138 * @param dataY - The range of data representing Y values.
139 * @param dataX - The range of data representing X values.
140 * @returns {number[]}
141 * @constructor
142 */
143var LINEST = function (dataY, dataX) {
144 ArgsChecker_1.ArgsChecker.checkLength(arguments, 2, "LINEST");
145 var rangeY = Filter_1.Filter.flattenAndThrow(dataY).map(function (value) {
146 return TypeConverter_1.TypeConverter.valueToNumber(value);
147 });
148 var rangeX = Filter_1.Filter.flattenAndThrow(dataX).map(function (value) {
149 return TypeConverter_1.TypeConverter.valueToNumber(value);
150 });
151 if (rangeX.length < 2) {
152 throw new Errors_1.NAError("LINEST requires more data points. Expected: 2, found: " + rangeX.length + ".");
153 }
154 if (rangeY.length < 2) {
155 throw new Errors_1.NAError("LINEST requires more data points. Expected: 2, found: " + rangeY.length + ".");
156 }
157 var xMean = MathHelpers_1.mean(rangeX);
158 var yMean = MathHelpers_1.mean(rangeY);
159 var n = rangeX.length;
160 var num = 0;
161 var den = 0;
162 for (var i = 0; i < n; i++) {
163 num += (rangeX[i] - xMean) * (rangeY[i] - yMean);
164 den += Math.pow(rangeX[i] - xMean, 2);
165 }
166 var m = num / den;
167 var b = yMean - m * xMean;
168 return [m, b];
169};
170exports.LINEST = LINEST;