Skip to content

Commit fe8b96e

Browse files
committed
feat(stats/incr): add nancovariance 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: na - 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: na - task: lint_typescript_tests status: na - task: lint_license_headers status: passed ---
1 parent 40b4245 commit fe8b96e

File tree

7 files changed

+387
-0
lines changed

7 files changed

+387
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2020 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
'use strict';
19+
20+
// MODULES //
21+
22+
var bench = require( '@stdlib/bench' );
23+
var randu = require( '@stdlib/random/base/randu' );
24+
var pkg = require( './../package.json' ).name;
25+
var nancovariance = require( './../lib' );
26+
27+
28+
// MAIN //
29+
30+
bench( pkg, function benchmark( b ) {
31+
var acc;
32+
var i;
33+
b.tic();
34+
for ( i = 0; i < b.iterations; i++ ) {
35+
acc = nancovariance();
36+
if ( typeof acc !== 'function' ) {
37+
b.fail( 'should return a function' );
38+
}
39+
}
40+
b.toc();
41+
if ( typeof acc !== 'function' ) {
42+
b.fail( 'should return a function' );
43+
}
44+
b.pass( 'benchmark finished' );
45+
b.end();
46+
});
47+
48+
bench( pkg+'::accumulator', function benchmark( b ) {
49+
var acc;
50+
var x;
51+
var y;
52+
var v;
53+
var i;
54+
55+
acc = nancovariance();
56+
57+
b.tic();
58+
for ( i = 0; i < b.iterations; i++ ) {
59+
x = ( randu() < 0.1 ) ? NaN : randu()*10; // ~10% NaN
60+
y = ( randu() < 0.1 ) ? NaN : randu()*10; // ~10% NaN
61+
v = acc( x, y );
62+
if ( v !== v && i > 1 ) {
63+
b.fail( 'accumulator should not return NaN once enough valid data' );
64+
}
65+
}
66+
b.toc();
67+
if ( v !== v ) {
68+
b.fail( 'should not return NaN' );
69+
}
70+
b.pass( 'benchmark finished' );
71+
b.end();
72+
});
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{{alias}}()
2+
Returns an accumulator function which incrementally updates a count,
3+
ignoring `NaN` values.
4+
5+
If provided a value, the accumulator function returns an updated count. If
6+
not provided a value, the accumulator function returns the current count.
7+
8+
Returns
9+
-------
10+
acc: Function
11+
Accumulator function.
12+
13+
Examples
14+
--------
15+
> var accumulator = {{alias}}();
16+
> var v = accumulator()
17+
null
18+
> v = accumulator( 2.0 )
19+
null
20+
> v = accumulator( NaN )
21+
null
22+
> v = accumulator( -5.0 )
23+
NaN
24+
> v = accumulator()
25+
NaN
26+
27+
See Also
28+
--------
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2020 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
var nancovariance = require( './../lib' );
22+
23+
var acc = nancovariance();
24+
25+
var dataX = [ 2.0, 2.0, NaN, 3.0, 5.0 ];
26+
var dataY = [ 1.0, 5.0, 4.0, NaN, 5.0 ];
27+
28+
var i;
29+
var cov;
30+
for ( i = 0; i < dataX.length; i++ ) {
31+
cov = acc( dataX[ i ], dataY[ i ] );
32+
console.log( 'x=%s, y=%s, cov=%s', dataX[ i ], dataY[ i ], ( cov === null ) ? 'null' : cov.toString() );
33+
}
34+
35+
console.log( '\nFinal sample covariance:', acc() );
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2020 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
/**
22+
* Compute an incremental sample covariance while ignoring NaN values.
23+
*
24+
* @module @stdlib/stats/incr/nancovariance
25+
* @module @stdlib/stats/incr/nancovariance
26+
*
27+
* @example
28+
* var incrnancount = require( '@stdlib/stats/incr/nancovariance' );
29+
*
30+
* var accumulator = incrnancount();
31+
*
32+
* var nancount = accumulator();
33+
* // returns 0
34+
*
35+
* nancount = accumulator( 2.0 );
36+
* // returns 1
37+
*
38+
* nancount = accumulator( -5.0 );
39+
* // returns 2
40+
*
41+
* nancount = accumulator();
42+
* // returns 2
43+
*/
44+
45+
// MODULES //
46+
47+
var main = require( './main.js' );
48+
49+
50+
// EXPORTS //
51+
52+
module.exports = main;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* eslint-disable stdlib/jsdoc-no-space-aligned-asterisks */
2+
/**
3+
* @license Apache-2.0
4+
*
5+
* Copyright (c) 2020 The Stdlib Authors.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
'use strict';
21+
22+
// MODULES //
23+
24+
var isnan = require( '@stdlib/math/base/assert/is-nan' );
25+
26+
27+
// MAIN //
28+
29+
/**
30+
* Returns an accumulator function which incrementally computes a sample covariance.
31+
*
32+
* @returns {Function} accumulator function
33+
*
34+
* @example
35+
* var accumulator = nancovariance();
36+
*
37+
* var cov = accumulator();
38+
* // returns null
39+
*
40+
* cov = accumulator( 2.0, 1.0 );
41+
* // returns null
42+
*
43+
* cov = accumulator( 2.0, 5.0 );
44+
* // returns 0
45+
*
46+
* cov = accumulator();
47+
* // returns 0
48+
*/
49+
function nancovariance() {
50+
var meanX = 0.0;
51+
var meanY = 0.0;
52+
var n = 0;
53+
var C = 0.0;
54+
return accumulator;
55+
56+
/**
57+
* Updates and returns the sample covariance when provided two numeric arguments.
58+
* If no arguments are provided, returns the current sample covariance.
59+
*
60+
* @private
61+
* @param {number} [x] - new x value
62+
* @param {number} [y] - new y value
63+
* @returns {(number|null)} sample covariance or null
64+
*/
65+
function accumulator( x, y ) {
66+
var delta;
67+
var dy;
68+
if ( arguments.length === 0 ) {
69+
return ( n < 2 ) ? null : C / ( n - 1 );
70+
}
71+
if ( isnan( x ) || isnan( y ) ) {
72+
return ( n < 2 ) ? null : C / ( n - 1 );
73+
}
74+
n += 1;
75+
delta = x - meanX;
76+
meanX += delta / n;
77+
dy = y - meanY;
78+
meanY += dy / n;
79+
C += ( ( n - 1 ) / n ) * delta * dy;
80+
return ( n < 2 ) ? null : C / ( n - 1 );
81+
}
82+
}
83+
84+
85+
// EXPORTS //
86+
87+
module.exports = nancovariance;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
{
2+
"name": "@stdlib/stats/incr/nancovariance",
3+
"version": "0.0.0",
4+
"description": "Compute an incremental sample covariance while ignoring NaN values.",
5+
"license": "Apache-2.0",
6+
"author": {
7+
"name": "The Stdlib Authors",
8+
"url": "https://github.com/stdlib-js/stdlib/graphs/contributors"
9+
},
10+
"contributors": [
11+
{
12+
"name": "The Stdlib Authors",
13+
"url": "https://github.com/stdlib-js/stdlib/graphs/contributors"
14+
}
15+
],
16+
"main": "./lib",
17+
"directories": {
18+
"benchmark": "./benchmark",
19+
"doc": "./docs",
20+
"example": "./examples",
21+
"lib": "./lib",
22+
"test": "./test"
23+
},
24+
"types": "./docs/types",
25+
"scripts": {},
26+
"homepage": "https://github.com/stdlib-js/stdlib",
27+
"repository": {
28+
"type": "git",
29+
"url": "git://github.com/stdlib-js/stdlib.git"
30+
},
31+
"bugs": {
32+
"url": "https://github.com/stdlib-js/stdlib/issues"
33+
},
34+
"dependencies": {},
35+
"devDependencies": {},
36+
"engines": {
37+
"node": ">=0.10.0",
38+
"npm": ">2.7.0"
39+
},
40+
"os": [
41+
"aix",
42+
"darwin",
43+
"freebsd",
44+
"linux",
45+
"macos",
46+
"openbsd",
47+
"sunos",
48+
"win32",
49+
"windows"
50+
],
51+
"keywords": [
52+
"stdlib",
53+
"statistics",
54+
"covariance",
55+
"incremental",
56+
"accumulator",
57+
"nan",
58+
"sample covariance"
59+
]
60+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2018 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var tape = require( 'tape' );
24+
var nancovariance = require( './../lib' );
25+
26+
27+
// MAIN //
28+
29+
tape( 'main export is a function', function test( t ) {
30+
t.ok( true, __filename );
31+
t.strictEqual( typeof nancovariance, 'function', 'main export is a function' );
32+
t.end();
33+
});
34+
35+
// Additional tests...
36+
37+
tape( 'the accumulator returns null when no arguments are provided', function test( t ) {
38+
var acc = nancovariance();
39+
t.equal( acc(), null, 'returns null initially' );
40+
t.end();
41+
});
42+
43+
tape( 'the accumulator computes sample covariance correctly, skipping NaN values', function test( t ) {
44+
var acc = nancovariance();
45+
var cov;
46+
47+
cov = acc( 2.0, 1.0 );
48+
t.equal( cov, null, 'returns null with only one valid pair' );
49+
50+
cov = acc( 2.0, 5.0 );
51+
t.notEqual( cov, null, 'returns a numeric covariance with two valid pairs' );
52+
t.end();
53+
});

0 commit comments

Comments
 (0)