2323 */
2424
2525import { createSeries } from './Series.js'
26- import { createWeighedSeries } from './WeighedSeries.js'
2726import { createLabelledBinarySearchTree } from './BinarySearchTree.js'
2827
2928import loglevel from 'loglevel'
@@ -36,7 +35,7 @@ export function createTSLinearSeries (maxSeriesLength = 0) {
3635 const X = createSeries ( maxSeriesLength )
3736 const Y = createSeries ( maxSeriesLength )
3837 const weight = createSeries ( maxSeriesLength )
39- const WY = createWeighedSeries ( maxSeriesLength , undefined )
38+ const WY = createSeries ( maxSeriesLength )
4039 const A = createLabelledBinarySearchTree ( )
4140
4241 let _A = 0
@@ -63,7 +62,7 @@ export function createTSLinearSeries (maxSeriesLength = 0) {
6362 X . push ( x )
6463 Y . push ( y )
6564 weight . push ( w )
66- WY . push ( y , w )
65+ WY . push ( w * y )
6766
6867 // Calculate all the slopes of the newly added point
6968 if ( X . length ( ) > 1 ) {
@@ -131,7 +130,7 @@ export function createTSLinearSeries (maxSeriesLength = 0) {
131130 }
132131
133132 /**
134- * @returns {float } the R^2 as a goodness of fit indicator
133+ * @returns {float } the R^2 as a global goodness of fit indicator
135134 * It will automatically recalculate the _goodnessOfFit when it isn't defined
136135 * This lazy approach is intended to prevent unneccesary calculations, especially when there is a batch of datapoints
137136 * pushes from the TSQuadratic regressor processing its linear residu
@@ -140,13 +139,17 @@ export function createTSLinearSeries (maxSeriesLength = 0) {
140139 function goodnessOfFit ( ) {
141140 let i = 0
142141 let sse = 0
142+ calculateIntercept ( )
143143 if ( _goodnessOfFit === null ) {
144144 if ( X . length ( ) >= 2 ) {
145145 _sst = 0
146146
147+ // Calculate weighted R^2
148+ const weightedAverageY = WY . sum ( ) / weight . sum ( )
149+
147150 while ( i < X . length ( ) ) {
148151 sse += weight . get ( i ) * Math . pow ( Y . get ( i ) - projectX ( X . get ( i ) ) , 2 )
149- _sst += weight . get ( i ) * Math . pow ( Y . get ( i ) - WY . weighedAverage ( ) , 2 )
152+ _sst += weight . get ( i ) * Math . pow ( Y . get ( i ) - weightedAverageY , 2 )
150153 i ++
151154 }
152155
@@ -156,14 +159,14 @@ export function createTSLinearSeries (maxSeriesLength = 0) {
156159 break
157160 case ( sse > _sst ) :
158161 // This is a pretty bad fit as the error is bigger than just using the line for the average y as intercept
159- _goodnessOfFit = 0
162+ _goodnessOfFit = 0.01
160163 break
161164 case ( _sst !== 0 ) :
162165 _goodnessOfFit = 1 - ( sse / _sst )
163166 break
164167 default :
165168 // When SST = 0, R2 isn't defined
166- _goodnessOfFit = 0
169+ _goodnessOfFit = 0.01
167170 }
168171 } else {
169172 _goodnessOfFit = 0
@@ -190,14 +193,14 @@ export function createTSLinearSeries (maxSeriesLength = 0) {
190193 break
191194 case ( weightedSquaredError > _sst ) :
192195 // This is a pretty bad fit as the error is bigger than just using the line for the average y as intercept
193- return 0
196+ return 0.01
194197 break
195198 case ( _sst !== 0 ) :
196199 return Math . min ( Math . max ( 1 - ( ( weightedSquaredError * X . length ( ) ) / _sst ) , 0 ) , 1 )
197200 break
198201 default :
199202 // When _SST = 0, localGoodnessOfFit isn't defined
200- return 0
203+ return 0.01
201204 }
202205 /* eslint-enable no-unreachable */
203206 } else {
@@ -278,7 +281,7 @@ export function createTSLinearSeries (maxSeriesLength = 0) {
278281 }
279282
280283 /**
281- * @description This function is used for clearing data and state
284+ * @description This function is used for clearing data and state, bringing it back to its original state
282285 */
283286 function reset ( ) {
284287 if ( X . length ( ) > 0 ) {
0 commit comments