diff --git a/AUTHORS b/AUTHORS index 8eaa345e4..b7a19b5d2 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/embeddedDocs.js b/src/expression/embeddedDocs/embeddedDocs.js index e2adde8a9..9dd8a4e52 100644 --- a/src/expression/embeddedDocs/embeddedDocs.js +++ b/src/expression/embeddedDocs/embeddedDocs.js @@ -197,6 +197,7 @@ import { stdDocs } from './function/statistics/std.js' import { cumSumDocs } from './function/statistics/cumsum.js' import { sumDocs } from './function/statistics/sum.js' import { varianceDocs } from './function/statistics/variance.js' +import { corrDocs } from './function/statistics/corr.js' import { acosDocs } from './function/trigonometry/acos.js' import { acoshDocs } from './function/trigonometry/acosh.js' import { acotDocs } from './function/trigonometry/acot.js' @@ -543,6 +544,7 @@ export const embeddedDocs = { std: stdDocs, sum: sumDocs, variance: varianceDocs, + corr: corrDocs, // functions - trigonometry acos: acosDocs, diff --git a/src/expression/embeddedDocs/function/statistics/corr.js b/src/expression/embeddedDocs/function/statistics/corr.js new file mode 100644 index 000000000..397dcbdf8 --- /dev/null +++ b/src/expression/embeddedDocs/function/statistics/corr.js @@ -0,0 +1,22 @@ +export const corrDocs = { + name: 'corr', + category: 'Statistics', + syntax: [ + 'corr(A,B)' + ], + 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(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', + 'mean', + 'min', + 'median', + 'min', + 'prod', + 'std', + 'sum' + ] +} diff --git a/src/factoriesAny.js b/src/factoriesAny.js index 8d79c6755..d353f70c7 100644 --- a/src/factoriesAny.js +++ b/src/factoriesAny.js @@ -237,6 +237,7 @@ export { createMad } from './function/statistics/mad.js' export { createVariance } from './function/statistics/variance.js' export { createQuantileSeq } from './function/statistics/quantileSeq.js' export { createStd } from './function/statistics/std.js' +export { createCorr } from './function/statistics/corr.js' export { createCombinations } from './function/probability/combinations.js' export { createCombinationsWithRep } from './function/probability/combinationsWithRep.js' export { createGamma } from './function/probability/gamma.js' diff --git a/src/factoriesNumber.js b/src/factoriesNumber.js index 47f9a37e1..988eb27e0 100644 --- a/src/factoriesNumber.js +++ b/src/factoriesNumber.js @@ -263,6 +263,7 @@ export { createMad } from './function/statistics/mad.js' export { createVariance } from './function/statistics/variance.js' export { createQuantileSeq } from './function/statistics/quantileSeq.js' export { createStd } from './function/statistics/std.js' +export { createCorr } from './function/statistics/corr.js' // string export { createFormat } from './function/string/format.js' diff --git a/src/function/statistics/corr.js b/src/function/statistics/corr.js new file mode 100644 index 000000000..efaa905d6 --- /dev/null +++ b/src/function/statistics/corr.js @@ -0,0 +1,64 @@ +import { factory } from '../../utils/factory.js' +const name = 'corr' +const dependencies = ['typed', 'matrix', 'mean', 'sqrt', 'sum', 'add', 'subtract', 'multiply', 'pow', 'divide'] + +export const createCorr = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, sqrt, sum, add, subtract, multiply, pow, divide }) => { + /** + * Compute the correlation coefficient of a two list with values, For matrices, the matrix correlation coefficient is calculated. + * + * Syntax: + * + * math.corr(A, B) + * + * Examples: + * + * 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(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]])) // returns DenseMatrix [0.9569941688503644, 1] + * + * See also: + * + * median, mean, min, max, sum, prod, std, variance + * + * @param {Array | Matrix} A The first array or matrix to compute correlation coefficient + * @param {Array | Matrix} B The second array or matrix to compute correlation coefficient + * @return {*} The correlation coefficient + */ + return typed(name, { + '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 or matrices. + * @param {Array | Matrix} A + * @param {Array | Matrix} B + * @return {*} correlation coefficient + * @private + */ + 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) + } + } + 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/corr.test.js b/test/unit-tests/function/statistics/corr.test.js new file mode 100644 index 000000000..38071158c --- /dev/null +++ b/test/unit-tests/function/statistics/corr.test.js @@ -0,0 +1,21 @@ +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 () { + assert.throws(function () { corr() }) + }) + + it('should throw an error if called with an empty array', function () { + assert.throws(function () { corr([]) }) + }) +}) diff --git a/types/index.d.ts b/types/index.d.ts index 000122295..c14a05d3f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -2970,6 +2970,14 @@ declare namespace math { normalization: 'unbiased' | 'uncorrected' | 'biased' ): MathNumericType + /** + * Calculate the correlation coefficient between two matrix. + * @param {Array | Matrix} x The first array or matrix to compute correlation coefficient + * @param {Array | Matrix} y The second array or matrix to compute correlation coefficient + * @returns correlation coefficient + */ + corr(x: MathCollection, y: MathCollection): MathType + /************************************************************************* * String functions ************************************************************************/