Skip to content

Commit b42620d

Browse files
authored
Added weights to the TSLinearSeries
1 parent 07c37e7 commit b42620d

File tree

1 file changed

+13
-10
lines changed

1 file changed

+13
-10
lines changed

app/engine/utils/TSLinearSeries.js

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
*/
2424

2525
import { createSeries } from './Series.js'
26-
import { createWeighedSeries } from './WeighedSeries.js'
2726
import { createLabelledBinarySearchTree } from './BinarySearchTree.js'
2827

2928
import 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

Comments
 (0)