Skip to content

Commit c4cc10d

Browse files
committed
Refactor incrmvariance Implementation for NaN Handling
1 parent 9f18b24 commit c4cc10d

File tree

1 file changed

+10
-167
lines changed
  • lib/node_modules/@stdlib/stats/incr/nanmvariance/lib

1 file changed

+10
-167
lines changed

lib/node_modules/@stdlib/stats/incr/nanmvariance/lib/main.js

Lines changed: 10 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@
2020

2121
// MODULES //
2222

23-
var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive;
24-
var isNumber = require( '@stdlib/assert/is-number' ).isPrimitive;
2523
var isnan = require( '@stdlib/math/base/assert/is-nan' );
26-
var format = require( '@stdlib/string/format' );
24+
var incrmvariance = require( '@stdlib/stats/incr/mvariance' );
2725

2826

2927
// MAIN //
@@ -65,37 +63,13 @@ var format = require( '@stdlib/string/format' );
6563
* var accumulator = incrnanmvariance( 3, -2.0 );
6664
*/
6765
function incrnanmvariance( W, mean ) {
68-
var delta;
69-
var buf;
70-
var tmp;
71-
var M2;
72-
var mu;
73-
var d1;
74-
var d2;
75-
var N;
76-
var n;
77-
var i;
78-
79-
if ( !isPositiveInteger( W ) ) {
80-
throw new TypeError( format( 'invalid argument. Must provide a positive integer. Value: `%s`.', W ) );
81-
}
82-
83-
buf = [];
84-
n = W - 1;
85-
M2 = 0.0;
86-
i = -1;
87-
N = 0;
88-
66+
var acc;
8967
if ( arguments.length > 1 ) {
90-
if ( !isNumber( mean ) ) {
91-
throw new TypeError( format( 'invalid argument. Must provide a number. Value: `%s`.', mean ) );
92-
}
93-
mu = mean;
94-
return accumulator2;
68+
acc = incrmvariance( W, mean );
69+
} else {
70+
acc = incrmvariance( W );
9571
}
96-
97-
mu = 0.0;
98-
return accumulator1;
72+
return accumulator;
9973

10074
/**
10175
* If provided a value, the accumulator function returns an updated unbiased sample variance, ignoring NaN values. If not provided a value, the accumulator function returns the current unbiased sample variance.
@@ -104,145 +78,14 @@ function incrnanmvariance( W, mean ) {
10478
* @param {number} [x] - input value
10579
* @returns {(number|null)} unbiased sample variance or null
10680
*/
107-
function accumulator1( x ) {
81+
function accumulator( x ) {
10882
if ( arguments.length === 0 ) {
109-
if ( N === 0 ) {
110-
return null;
111-
}
112-
if ( N === 1 ) {
113-
return 0.0;
114-
}
115-
if ( N < W ) {
116-
return M2 / ( N - 1 );
117-
}
118-
return M2 / n;
83+
return acc();
11984
}
120-
12185
if ( isnan( x ) ) {
122-
if ( N === 0 ) {
123-
return null;
124-
}
125-
if ( N === 1 ) {
126-
return 0.0;
127-
}
128-
if ( N < W ) {
129-
return M2 / ( N - 1 );
130-
}
131-
return M2 / n;
86+
return acc();
13287
}
133-
134-
// Update the index for managing the circular buffer:
135-
i = ( i+1 ) % W;
136-
137-
// Case: initial window...
138-
if ( N < W ) {
139-
if ( N < W ) {
140-
buf.push( x );
141-
} else {
142-
buf[ i ] = x;
143-
}
144-
N += 1;
145-
delta = x - mu;
146-
mu += delta / N;
147-
M2 += delta * ( x - mu );
148-
if ( N === 1 ) {
149-
return 0.0;
150-
}
151-
return M2 / ( N-1 );
152-
}
153-
154-
// Case: N = W = 1
155-
if (N === 1) {
156-
M2 = 0.0;
157-
return M2;
158-
}
159-
160-
// Case: outgoing value is NaN, which we need to simply replace without affecting the variance
161-
if (isnan(buf[i])) {
162-
buf[i] = x;
163-
164-
// When replacing NaN with a value, update M2 with the squared difference from the mean
165-
M2 += (x - mu) * (x - mu);
166-
return M2 / n;
167-
}
168-
169-
// Case: standard update when neither incoming nor outgoing values are NaN
170-
tmp = buf[i];
171-
delta = x - tmp;
172-
d1 = tmp - mu;
173-
mu += delta / N;
174-
d2 = x - mu;
175-
M2 += delta * (d1 + d2);
176-
177-
buf[i] = x;
178-
return M2 / n;
179-
}
180-
181-
/**
182-
* If provided a value, the accumulator function returns an updated unbiased sample variance, ignoring NaN values. If not provided a value, the accumulator function returns the current unbiased sample variance.
183-
*
184-
* @private
185-
* @param {number} [x] - input value
186-
* @returns {(number|null)} unbiased sample variance or null
187-
*/
188-
function accumulator2( x ) {
189-
if ( arguments.length === 0 ) {
190-
if ( N === 0 ) {
191-
return null;
192-
}
193-
if ( N < W ) {
194-
return M2 / N;
195-
}
196-
return M2 / W;
197-
}
198-
199-
// If incoming value is NaN, ignore it:
200-
if ( isnan( x ) ) {
201-
if ( N === 0 ) {
202-
return null;
203-
}
204-
if (N < W) {
205-
return M2 / N;
206-
}
207-
return M2 / W;
208-
}
209-
210-
// Update the index for managing the circular buffer:
211-
i = (i+1) % W;
212-
213-
// Case: initial window...
214-
if ( N < W ) {
215-
if ( N < W ) {
216-
buf.push( x );
217-
} else {
218-
buf[ i ] = x;
219-
}
220-
N += 1;
221-
delta = x - mu;
222-
M2 += delta * delta;
223-
return M2 / N;
224-
}
225-
226-
// Case: outgoing value is NaN, which we need to simply replace without affecting the variance
227-
if ( isnan( buf[ i ] ) ) {
228-
buf[ i ] = x;
229-
230-
// Add the squared difference between the new value and mean
231-
M2 += (x - mu) * (x - mu);
232-
return M2 / W;
233-
}
234-
235-
// Case: standard update when neither incoming nor outgoing values are NaN
236-
tmp = buf[ i ];
237-
238-
// Remove the contribution of the outgoing value
239-
M2 -= ( tmp - mu ) * ( tmp - mu );
240-
241-
// Add the contribution of the incoming value
242-
M2 += ( x - mu ) * ( x - mu );
243-
244-
buf[ i ] = x;
245-
return M2 / W;
88+
return acc( x );
24689
}
24790
}
24891

0 commit comments

Comments
 (0)