From d6a403a04824b6d805449f42cd4574e7fddead35 Mon Sep 17 00:00:00 2001 From: vrushaket Date: Wed, 23 Aug 2023 23:06:32 +0530 Subject: [PATCH] added implemenation for signature Matrix, Matrix and support for BigNumbers --- AUTHORS | 1 + .../function/statistics/correlation.js | 5 +- src/function/statistics/correlation.js | 69 +++++++++---------- .../function/statistics/correlation.test.js | 3 + types/index.d.ts | 13 ++-- 5 files changed, 45 insertions(+), 46 deletions(-) diff --git a/AUTHORS b/AUTHORS index 8eaa345e4b..b7a19b5d27 100644 --- a/AUTHORS +++ b/AUTHORS @@ -231,5 +231,6 @@ MaybePixem <47889538+MaybePixem@users.noreply.github.com> Aly Khaled BuildTools Anik Patel <74193405+Bobingstern@users.noreply.github.com> +vrushaket # Generated by tools/update-authors.js diff --git a/src/expression/embeddedDocs/function/statistics/correlation.js b/src/expression/embeddedDocs/function/statistics/correlation.js index 3bcedf3d13..6e59defdeb 100644 --- a/src/expression/embeddedDocs/function/statistics/correlation.js +++ b/src/expression/embeddedDocs/function/statistics/correlation.js @@ -4,9 +4,10 @@ export const correlationDocs = { syntax: [ 'corr(A,B)' ], - description: 'Compute the colleration of a two list with values', + description: 'Compute the correlation coefficient of a two list with values, For matrices, the matrix correlation coefficient is calculated.', examples: [ - 'corr([2, 4, 6, 8],[1, 2, 3, 6])' + 'corr([2, 4, 6, 8],[1, 2, 3, 6])', + 'corr(matrix([[1, 2.2, 3, 4.8, 5], [1, 2, 3, 4, 5]]), matrix([[4, 5.3, 6.6, 7, 8], [1, 2, 3, 4, 5]]))' ], seealso: [ 'max', diff --git a/src/function/statistics/correlation.js b/src/function/statistics/correlation.js index cd0b764387..5beb828400 100644 --- a/src/function/statistics/correlation.js +++ b/src/function/statistics/correlation.js @@ -1,11 +1,10 @@ import { factory } from '../../utils/factory.js' - const name = 'corr' -const dependencies = ['typed'] +const dependencies = ['typed', 'matrix', 'mean', 'sqrt', 'sum', 'add', 'subtract', 'multiply', 'pow', 'divide'] -export const createCorrelation = /* #__PURE__ */ factory(name, dependencies, ({ typed }) => { +export const createCorrelation = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, sqrt, sum, add, subtract, multiply, pow, divide }) => { /** - * Compute the colleration of a two list with values. + * Compute the correlation coefficient of a two list with values, For matrices, the matrix correlation coefficient is calculated. * * Syntax: * @@ -15,46 +14,44 @@ export const createCorrelation = /* #__PURE__ */ factory(name, dependencies, ({ * * math.corr([1, 2, 3, 4, 5], [4, 5, 6, 7, 8]) // returns 1 * math.corr([1, 2.2, 3, 4.8, 5], [4, 5.3, 6.6, 7, 8]) // returns 0.9569941688503644 + * math.corr(matrix([[1, 2.2, 3, 4.8, 5], [1, 2, 3, 4, 5]]), matrix([[4, 5.3, 6.6, 7, 8], [1, 2, 3, 4, 5]])) // returns [0.9569941688503644, 1]) * */ return typed(name, { - // correlation(xArray, yArray) - 'Array, Array': function (xArray, yArray) { - return _corr(xArray, yArray) + 'Array, Array': function (A, B) { + return _corr(A, B) + }, + 'Matrix, Matrix': function (xMatrix, yMatrix) { + return matrix(_corr(xMatrix.toArray(), yMatrix.toArray())) } }) /** - * Calculate the correlation coefficient between two arrays. - * @param {Array} xArray - * @param {Array} yArray - * @return {number | BigNumber} correlation coefficient + * Calculate the correlation coefficient between two arrays or matrices. + * @param {Array | Matrix} A + * @param {Array | Matrix} B + * @return {*} correlation coefficient * @private */ - function _corr (xArray, yArray, normalization) { - if (xArray.length !== yArray.length) { - throw new SyntaxError('Input arrays must have the same length') - } - if (xArray.length < 2) { - throw new SyntaxError('Function corr requires two or more parameters (' + xArray.length + ' provided) in first input array') - } - if (yArray.length < 2) { - throw new SyntaxError('Function corr requires two or more parameters (' + yArray.length + ' provided) in second input array') + function _corr (A, B) { + if (Array.isArray(A[0]) && Array.isArray(B[0])) { + const correlations = [] + for (let i = 0; i < A.length; i++) { + correlations.push(correlation(A[i], B[i])) + } + return correlations + } else { + return correlation(A, B) } - - const n = xArray.length - - const sumX = xArray.reduce((acc, x) => acc + x, 0) - const sumY = yArray.reduce((acc, y) => acc + y, 0) - - const sumXY = xArray.reduce((acc, x, index) => acc + x * yArray[index], 0) - const sumXSquare = xArray.reduce((acc, x) => acc + x ** 2, 0) - const sumYSquare = yArray.reduce((acc, y) => acc + y ** 2, 0) - - const numerator = n * sumXY - sumX * sumY - const denominator = Math.sqrt((n * sumXSquare - sumX ** 2) * (n * sumYSquare - sumY ** 2)) - - const correlation = numerator / denominator - - return correlation + } + function correlation (A, B) { + const n = A.length + const sumX = sum(A) + const sumY = sum(B) + const sumXY = A.reduce((acc, x, index) => add(acc, multiply(x, B[index])), 0) + const sumXSquare = sum(A.map(x => pow(x, 2))) + const sumYSquare = sum(B.map(y => pow(y, 2))) + const numerator = subtract(multiply(n, sumXY), multiply(sumX, sumY)) + const denominator = sqrt(multiply(subtract(multiply(n, sumXSquare), pow(sumX, 2)), subtract(multiply(n, sumYSquare), pow(sumY, 2)))) + return divide(numerator, denominator) } }) diff --git a/test/unit-tests/function/statistics/correlation.test.js b/test/unit-tests/function/statistics/correlation.test.js index 5ff8c7106a..38071158c2 100644 --- a/test/unit-tests/function/statistics/correlation.test.js +++ b/test/unit-tests/function/statistics/correlation.test.js @@ -1,11 +1,14 @@ import assert from 'assert' import math from '../../../../src/defaultInstance.js' const corr = math.corr +const BigNumber = math.BigNumber describe('correlation', function () { it('should return the correlation coefficient from an array', function () { + assert.strictEqual(corr([new BigNumber(1), new BigNumber(2.2), new BigNumber(3), new BigNumber(4.8), new BigNumber(5)], [new BigNumber(4), new BigNumber(5.3), new BigNumber(6.6), new BigNumber(7), new BigNumber(8)]).toNumber(), 0.9569941688503653) assert.strictEqual(corr([1, 2, 3, 4, 5], [4, 5, 6, 7, 8]), 1) assert.strictEqual(corr([1, 2.2, 3, 4.8, 5], [4, 5.3, 6.6, 7, 8]), 0.9569941688503644) + assert.deepStrictEqual(corr(math.matrix([[1, 2.2, 3, 4.8, 5], [1, 2, 3, 4, 5]]), math.matrix([[4, 5.3, 6.6, 7, 8], [1, 2, 3, 4, 5]]))._data, [0.9569941688503644, 1]) }) it('should throw an error if called with invalid number of arguments', function () { diff --git a/types/index.d.ts b/types/index.d.ts index 54ef9fabdd..441777ac09 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -2915,8 +2915,8 @@ declare namespace math { cumsum(...args: MathType[]): MathType[] /** * @param array A single matrix - * @p corr(xArray: MathCollection, yArray: MathCollection): MathNumericType -ms along the given dimension + * @param dim The dimension along which to sum (defaults to 0) + * @returns The cumulative sums along the given dimension */ cumsum(array: MathCollection, dim?: number): MathCollection @@ -2972,14 +2972,11 @@ ms along the given dimension /** * Calculate the correlation coefficient between two matrix. - * @param {Array} xArray A matrix to compute correlation coefficient - * @param {Array} yArray A matrix to compute correlation coefficient + * @param {Array} x The first matrix to compute correlation coefficient + * @param {Array} y The second matrix to compute correlation coefficient * @returns correlation coefficient */ - corr( - xArray: MathCollection, - yArray: MathCollection - ): MathNumericType + corr(xArray: MathCollection, yArray: MathCollection): MathType /************************************************************************* * String functions