From 8481f495fd8ec7a6ba6309d8a1ff54ec594a46db Mon Sep 17 00:00:00 2001 From: Jayhari Aditiya Date: Sat, 15 Mar 2025 13:18:37 +0530 Subject: [PATCH] feat(stats/incr): add incrnanmae accumulator --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: passed - task: lint_package_json status: passed - task: lint_repl_help status: passed - task: lint_javascript_src status: passed - task: lint_javascript_cli status: na - task: lint_javascript_examples status: passed - task: lint_javascript_tests status: passed - task: lint_javascript_benchmarks status: passed - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: passed - task: lint_license_headers status: passed --- --- .../@stdlib/stats/incr/nanmae/README.md | 175 ++++++++++++++++++ .../stats/incr/nanmae/benchmark/benchmark.js | 105 +++++++++++ .../docs/img/equation_mean_absolute_error.svg | 54 ++++++ .../@stdlib/stats/incr/nanmae/docs/repl.txt | 36 ++++ .../stats/incr/nanmae/docs/types/index.d.ts | 70 +++++++ .../stats/incr/nanmae/docs/types/test.ts | 72 +++++++ .../stats/incr/nanmae/examples/index.js | 41 ++++ .../@stdlib/stats/incr/nanmae/lib/index.js | 60 ++++++ .../@stdlib/stats/incr/nanmae/lib/main.js | 84 +++++++++ .../@stdlib/stats/incr/nanmae/package.json | 67 +++++++ .../@stdlib/stats/incr/nanmae/test/test.js | 115 ++++++++++++ 11 files changed, 879 insertions(+) create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/README.md create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/benchmark/benchmark.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/docs/img/equation_mean_absolute_error.svg create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/docs/repl.txt create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/docs/types/index.d.ts create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/docs/types/test.ts create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/examples/index.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/lib/index.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/lib/main.js create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/package.json create mode 100644 lib/node_modules/@stdlib/stats/incr/nanmae/test/test.js diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/README.md b/lib/node_modules/@stdlib/stats/incr/nanmae/README.md new file mode 100644 index 000000000000..0a8dbc6afa1e --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/README.md @@ -0,0 +1,175 @@ + + +# incrnanmae + +> Compute the [mean absolute error][mean-absolute-error] (MAE) incrementally, ignoring `NaN` values. + +
+ +The [mean absolute error][mean-absolute-error] is defined as + + + +```math +\mathop{\mathrm{MAE}} = \frac{\displaystyle\sum_{i=0}^{n-1} |y_i - x_i|}{n} +``` + + + + + +
+ + + +
+ +## Usage + +```javascript +var incrnanmae = require( '@stdlib/stats/incr/nanmae' ); +``` + +#### incrnanmae() + +Returns an accumulator `function` which incrementally computes the [mean absolute error][mean-absolute-error] ignoring NaN values. + +```javascript +var accumulator = incrnanmae(); +``` + +#### accumulator( \[x, y] ) + +If provided input values `x` and `y`, the accumulator function returns an updated [mean absolute error][mean-absolute-error]. If not provided input values `x` and `y`, the accumulator function returns the current [mean absolute error][mean-absolute-error]. + +```javascript +var accumulator = incrnanmae(); + +var m = accumulator(); +// returns null + +m = accumulator( 2.0, 3.0 ); +// returns 1.0 + +m = accumulator( NaN, 2.0 ); +// returns 1.0 + +m = accumulator( -5.0, NaN ); +// returns 1.0 + +m = accumulator( NaN, NaN ); +// returns 1.0 + +m = accumulator( -5.0, 2.0 ); +// returns 4.0 + +m = accumulator(); +// returns 4.0 +``` + +
+ + + +
+ +## Notes + +- Input values are not type checked beyond checking for NaN. If provided values which are not numbers or NaN (e.g., strings, booleans), the behavior of the accumulator is undefined. If non-numeric inputs are possible, you are advised to type check and handle accordingly before passing the value to the accumulator function. +- If both provided values are NaN, the accumulated value is unchanged. The accumulator only updates when both inputs are valid numbers. +- **Warning**: the [mean absolute error][mean-absolute-error] is scale-dependent and, thus, the measure should **not** be used to make comparisons between datasets having different scales. + +
+ + + +
+ +## Examples + + + +```javascript +var randu = require( '@stdlib/random/base/randu' ); +var incrnanmae = require( '@stdlib/stats/incr/nanmae' ); + +var accumulator; +var v1; +var v2; +var i; + +// Initialize an accumulator: +accumulator = incrnanmae(); + +// For each simulated datum, update the mean absolute error... +for ( i = 0; i < 100; i++ ) { + v1 = ( randu() < 0.2 ) ? NaN : ( randu()*100.0 ) - 50.0; + v2 = ( randu() < 0.2 ) ? NaN : ( randu()*100.0 ) - 50.0; + accumulator( v1, v2 ); +} +console.log( accumulator() ); +``` + +
+ + + + + + + + + + + + + + diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/benchmark/benchmark.js b/lib/node_modules/@stdlib/stats/incr/nanmae/benchmark/benchmark.js new file mode 100644 index 000000000000..287889ceafa2 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/benchmark/benchmark.js @@ -0,0 +1,105 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var bench = require( '@stdlib/bench' ); +var randu = require( '@stdlib/random/base/randu' ); +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var pkg = require( './../package.json' ).name; +var incrnanmae = require( './../lib' ); // Corrected from incrmae + + +// MAIN // + +bench( pkg, function benchmark( b ) { + var f; + var i; + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + f = incrnanmae(); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + } + b.toc(); + if ( typeof f !== 'function' ) { + b.fail( 'should return a function' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+'::accumulator', function benchmark( b ) { + var acc; + var v; + var i; + var x; + var y; + + acc = incrnanmae(); + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + x = ( randu() < 0.2 ) ? NaN : randu()-0.5; + y = ( randu() < 0.2 ) ? NaN : randu()-0.5; + v = acc( x, y ); + if ( v !== v && !isnan( x ) && !isnan( y ) ) { + b.fail( 'should not return NaN when inputs are not NaN' ); + } + } + b.toc(); + if ( v !== v && !isnan( x ) && !isnan( y ) ) { + b.fail( 'should not return NaN when inputs are not NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); + +bench( pkg+'::accumulator,nan_handling', function benchmark( b ) { + var acc; + var v; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + acc = incrnanmae(); // Reset accumulator for each iteration + v = acc(); // Initial state + if ( v !== null ) { + b.fail( 'initial value should be null' ); + } + acc( 2.0, 3.0 ); // Set a baseline MAE + v = acc( NaN, randu()-0.5 ); + if ( typeof v !== 'number' || isnan( v ) ) { + b.fail( 'should return a number when one input is NaN' ); + } + v = acc( randu()-0.5, NaN ); + if ( typeof v !== 'number' || isnan( v ) ) { + b.fail( 'should return a number when one input is NaN' ); + } + v = acc( NaN, NaN ); + if ( typeof v !== 'number' || isnan( v ) ) { + b.fail( 'should return a number when both inputs are NaN' ); + } + } + b.toc(); + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/docs/img/equation_mean_absolute_error.svg b/lib/node_modules/@stdlib/stats/incr/nanmae/docs/img/equation_mean_absolute_error.svg new file mode 100644 index 000000000000..8ca0b90df05f --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/docs/img/equation_mean_absolute_error.svg @@ -0,0 +1,54 @@ + +upper M upper A upper E equals StartFraction sigma-summation Underscript i equals 0 Overscript n minus 1 Endscripts StartAbsoluteValue y Subscript i Baseline minus x Subscript i Baseline EndAbsoluteValue Over n EndFraction + + + \ No newline at end of file diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/docs/repl.txt b/lib/node_modules/@stdlib/stats/incr/nanmae/docs/repl.txt new file mode 100644 index 000000000000..7c907d14fe40 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/docs/repl.txt @@ -0,0 +1,36 @@ + +{{alias}}() + Returns an accumulator function which incrementally computes the mean + absolute error, ignoring `NaN` values. + + If provided two values, the accumulator function returns an updated mean + absolute error. If not provided values, the accumulator function returns + the current mean absolute error. + + Returns + ------- + acc: Function + Accumulator function. + + Examples + -------- + > var incrnanmae = require( '@stdlib/stats/incr/nanmae' ); + > var accumulator = incrnanmae(); + > var m = accumulator() + null + > m = accumulator( 2.0, 3.0 ) + 1.0 + > m = accumulator( NaN, 2.0 ) + 1.0 + > m = accumulator( -5.0, NaN ) + 1.0 + > m = accumulator( NaN, NaN ) + 1.0 + > m = accumulator( -5.0, 2.0 ) + 4.0 + > m = accumulator() + 4.0 + + See Also + -------- + diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/docs/types/index.d.ts b/lib/node_modules/@stdlib/stats/incr/nanmae/docs/types/index.d.ts new file mode 100644 index 000000000000..3752fc459795 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/docs/types/index.d.ts @@ -0,0 +1,70 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +// TypeScript Version: 4.1 + +/// + +/** +* If provided input values, the accumulator function returns an updated mean absolute error. If not provided input values, the accumulator function returns the current mean absolute error. +* +* ## Notes +* +* - If either provided value is `NaN`, the accumulated value is unchanged and remains the current mean absolute error (or `null` if no valid values have been provided). +* +* @param x - input value +* @param y - input value +* @returns mean absolute error or null +*/ +type accumulator = ( x?: number, y?: number ) => number | null; + +/** +* Returns an accumulator function which incrementally computes the mean absolute error, ignoring `NaN` values. +* +* @returns accumulator function +* +* @example +* var accumulator = incrnanmae(); +* +* var m = accumulator(); +* // returns null +* +* m = accumulator( 2.0, 3.0 ); +* // returns 1.0 +* +* m = accumulator( NaN, 2.0 ); +* // returns 1.0 +* +* m = accumulator( -5.0, NaN ); +* // returns 1.0 +* +* m = accumulator( NaN, NaN ); +* // returns 1.0 +* +* m = accumulator( -5.0, 2.0 ); +* // returns 4.0 +* +* m = accumulator(); +* // returns 4.0 +*/ +declare function incrnanmae(): accumulator; + + +// EXPORTS // + +export = incrnanmae; diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/docs/types/test.ts b/lib/node_modules/@stdlib/stats/incr/nanmae/docs/types/test.ts new file mode 100644 index 000000000000..8002fcff4beb --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/docs/types/test.ts @@ -0,0 +1,72 @@ +/* +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import incrnanmae = require( './index' ); + + +// TESTS // + +// The function returns an accumulator function... +{ + incrnanmae(); // $ExpectType accumulator +} + +// The compiler throws an error if the function is provided arguments... +{ + incrnanmae( '5' ); // $ExpectError + incrnanmae( 5 ); // $ExpectError + incrnanmae( true ); // $ExpectError + incrnanmae( false ); // $ExpectError + incrnanmae( null ); // $ExpectError + incrnanmae( undefined ); // $ExpectError + incrnanmae( [] ); // $ExpectError + incrnanmae( {} ); // $ExpectError + incrnanmae( ( x: number ): number => x ); // $ExpectError +} + +// The function returns an accumulator function which returns an accumulated result... +{ + const acc = incrnanmae(); + + acc(); // $ExpectType number | null + acc( 3.14, 2.0 ); // $ExpectType number | null + acc( NaN, 2.0 ); // $ExpectType number | null + acc( -5.0, NaN ); // $ExpectType number | null + acc( NaN, NaN ); // $ExpectType number | null +} + +// The compiler throws an error if the returned accumulator function is provided invalid arguments... +{ + const acc = incrnanmae(); + + acc( '5', 2.0 ); // $ExpectError + acc( true, 2.0 ); // $ExpectError + acc( false, 2.0 ); // $ExpectError + acc( null, 2.0 ); // $ExpectError + acc( [], 2.0 ); // $ExpectError + acc( {}, 2.0 ); // $ExpectError + acc( ( x: number ): number => x, 2.0 ); // $ExpectError + + acc( 3.14, '5' ); // $ExpectError + acc( 3.14, true ); // $ExpectError + acc( 3.14, false ); // $ExpectError + acc( 3.14, null ); // $ExpectError + acc( 3.14, [] ); // $ExpectError + acc( 3.14, {} ); // $ExpectError + acc( 3.14, ( x: number ): number => x ); // $ExpectError +} diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/examples/index.js b/lib/node_modules/@stdlib/stats/incr/nanmae/examples/index.js new file mode 100644 index 000000000000..407d45eda10a --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/examples/index.js @@ -0,0 +1,41 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +var randu = require( '@stdlib/random/base/randu' ); +var incrnanmae = require( './../lib' ); + +var accumulator; +var err; +var v1; +var v2; +var i; + +// Initialize an accumulator: +accumulator = incrnanmae(); + +// For each simulated datum, update the mean absolute error... +console.log( '\nValue\tValue\tMean\n' ); +for ( i = 0; i < 100; i++ ) { + v1 = ( randu() < 0.2 ) ? NaN : ( randu()*100.0 ) - 50.0; + v2 = ( randu() < 0.2 ) ? NaN : ( randu()*100.0 ) - 50.0; + err = accumulator( v1, v2 ); + console.log( '%d\t%d\t%d', v1.toFixed( 3 ), v2.toFixed( 3 ), err.toFixed( 3 ) ); +} +console.log( '\nFinal MAE: %d\n', accumulator() ); diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/lib/index.js b/lib/node_modules/@stdlib/stats/incr/nanmae/lib/index.js new file mode 100644 index 000000000000..4c736e68e65b --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/lib/index.js @@ -0,0 +1,60 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +/** +* Compute the mean absolute error incrementally, ignoring NaN values. +* +* @module @stdlib/stats/incr/nanmae +* +* @example +* var incrnanmae = require( '@stdlib/stats/incr/nanmae' ); +* +* var accumulator = incrnanmae(); +* +* var m = accumulator(); +* // returns null +* +* m = accumulator( 2.0, 3.0 ); +* // returns 1.0 +* +* m = accumulator( NaN, 2.0 ); +* // returns 1.0 +* +* m = accumulator( -5.0, NaN ); +* // returns 1.0 +* +* m = accumulator( NaN, NaN ); +* // returns 1.0 +* +* m = accumulator( -5.0, 2.0 ); +* // returns 4.0 +* +* m = accumulator(); +* // returns 4.0 +*/ + +// MODULES // + +var main = require( './main.js' ); + + +// EXPORTS // + +module.exports = main; diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/lib/main.js b/lib/node_modules/@stdlib/stats/incr/nanmae/lib/main.js new file mode 100644 index 000000000000..a77f39707440 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/lib/main.js @@ -0,0 +1,84 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var incrmae = require( '@stdlib/stats/incr/mae' ); + + +// MAIN // + +/** +* Returns an accumulator function which incrementally computes the mean absolute error, ignoring NaN values. +* +* @returns {Function} accumulator function +* +* @example +* var accumulator = incrnanmae(); +* +* var m = accumulator(); +* // returns null +* +* m = accumulator( 2.0, 3.0 ); +* // returns 1.0 +* +* m = accumulator( NaN, 2.0 ); +* // returns 1.0 +* +* m = accumulator( -5.0, NaN ); +* // returns 1.0 +* +* m = accumulator( NaN, NaN ); +* // returns 1.0 +* +* m = accumulator( -5.0, 2.0 ); +* // returns 4.0 +* +* m = accumulator(); +* // returns 4.0 +*/ +function incrnanmae() { + var mae = incrmae(); + return accumulator; + + /** + * If provided input values, the accumulator function returns an updated mean absolute error. If not provided input values, the accumulator function returns the current mean absolute error. + * + * @private + * @param {number} [x] - input value + * @param {number} [y] - input value + * @returns {(number|null)} mean absolute error or null + */ + function accumulator( x, y ) { + if ( arguments.length === 0 ) { + return mae(); + } + if ( isnan( x ) || isnan( y ) ) { + return mae(); + } + return mae( x, y ); + } +} + + +// EXPORTS // + +module.exports = incrnanmae; diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/package.json b/lib/node_modules/@stdlib/stats/incr/nanmae/package.json new file mode 100644 index 000000000000..3268526505e7 --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/package.json @@ -0,0 +1,67 @@ +{ + "name": "@stdlib/stats/incr/nanmae", + "version": "0.0.0", + "description": "Compute the mean absolute error incrementally, ignoring NaN values..", + "license": "Apache-2.0", + "author": { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + }, + "contributors": [ + { + "name": "The Stdlib Authors", + "url": "https://github.com/stdlib-js/stdlib/graphs/contributors" + } + ], + "main": "./lib", + "directories": { + "benchmark": "./benchmark", + "doc": "./docs", + "example": "./examples", + "lib": "./lib", + "test": "./test" + }, + "types": "./docs/types", + "scripts": {}, + "homepage": "https://github.com/stdlib-js/stdlib", + "repository": { + "type": "git", + "url": "git://github.com/stdlib-js/stdlib.git" + }, + "bugs": { + "url": "https://github.com/stdlib-js/stdlib/issues" + }, + "dependencies": {}, + "devDependencies": {}, + "engines": { + "node": ">=0.10.0", + "npm": ">2.7.0" + }, + "os": [ + "aix", + "darwin", + "freebsd", + "linux", + "macos", + "openbsd", + "sunos", + "win32", + "windows" + ], + "keywords": [ + "stdlib", + "stdmath", + "statistics", + "stats", + "mathematics", + "math", + "absolute", + "avg", + "mean", + "arithmetic mean", + "central tendency", + "error", + "incremental", + "accumulator" + ] +} diff --git a/lib/node_modules/@stdlib/stats/incr/nanmae/test/test.js b/lib/node_modules/@stdlib/stats/incr/nanmae/test/test.js new file mode 100644 index 000000000000..bc9d044ec11b --- /dev/null +++ b/lib/node_modules/@stdlib/stats/incr/nanmae/test/test.js @@ -0,0 +1,115 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2020 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var tape = require( 'tape' ); +var abs = require( '@stdlib/math/base/special/abs' ); +var EPS = require( '@stdlib/constants/float64/eps' ); +var incrnanmae = require( './../lib' ); + + +// TESTS // + +tape( 'main export is a function', function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof incrnanmae, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function returns an accumulator function', function test( t ) { + t.equal( typeof incrnanmae(), 'function', 'returns a function' ); + t.end(); +}); + +tape( 'the initial accumulated value is `null`', function test( t ) { + var acc = incrnanmae(); + t.equal( acc(), null, 'returns expected value' ); + t.end(); +}); + +tape( 'the accumulator function incrementally computes the mean absolute error, ignoring NaN values', function test( t ) { + var expected; + var actual; + var delta; + var data; + var acc; + var sum; + var tol; + var N; + var n; + var x; + var y; + var i; + + data = [ + [ 2.0, 3.0 ], // MAE = |2-3| / 1 = 1.0 + [ 3.0, NaN ], // Ignored, MAE = 1.0 + [ NaN, 5.0 ], // Ignored, MAE = 1.0 + [ 4.0, -4.0 ], // MAE = (1 + |4-(-4)|) / 2 = 4.5 + [ NaN, NaN ], // Ignored, MAE = 4.5 + [ -4.0, 5.0 ] // MAE = (1 + 8 + |-4-5|) / 3 = 6.0 + ]; + N = data.length; + + acc = incrnanmae(); + + sum = 0; + n = 0; // Count of valid pairs + for ( i = 0; i < N; i++ ) { + x = data[ i ][ 0 ]; + y = data[ i ][ 1 ]; + if ( !isNaN( x ) && !isNaN( y ) ) { + sum += abs( y-x ); + n += 1; + expected = sum / n; + } else { + expected = ( n === 0 ) ? null : sum / n; + } + actual = acc( x, y ); + if ( actual === expected ) { + t.equal( actual, expected, 'returns expected value' ); + } else { + delta = abs( expected - actual ); + tol = 1.0 * EPS * abs( expected ); + t.equal( delta <= tol, true, 'within tolerance. Actual: '+actual+'. Expected: '+expected+'. Delta: '+delta+'. Tol: '+tol+'.' ); + } + } + t.end(); +}); + +tape( 'if not provided an input value, the accumulator function returns the current mean absolute error', function test( t ) { + var data; + var acc; + var i; + + data = [ + [ 2.0, 3.0 ], // MAE = 1.0 + [ NaN, -5.0 ], // Ignored, MAE = 1.0 + [ 1.0, NaN ], // Ignored, MAE = 1.0 + [ 1.0, 10.0 ] // MAE = (1 + |1-10|) / 2 = 5.0 + ]; + acc = incrnanmae(); + for ( i = 0; i < data.length; i++ ) { + acc( data[ i ][ 0 ], data[ i ][ 1 ] ); + } + t.equal( acc(), 5.0, 'returns expected value' ); + t.end(); +});