|
|
@@ -1,6 +1,9 @@
|
|
|
import differenceInDays from 'date-fns/differenceInDays';
|
|
|
import { Cases, Data } from '../types';
|
|
|
|
|
|
+// Start the regression line after this many cases have been recorded in total
|
|
|
+const regressionStart = 50;
|
|
|
+
|
|
|
const mean = (values: number[]): number =>
|
|
|
values.reduce((last, value) => last + value, 0) / values.length;
|
|
|
|
|
|
@@ -9,11 +12,36 @@ export function getExponentialRegression(cases: Cases): Data {
|
|
|
return [];
|
|
|
}
|
|
|
|
|
|
+ const { index: startIndex } = cases.reduce(
|
|
|
+ ({ sum, index }, { value }, nextIndex) => {
|
|
|
+ if (sum >= regressionStart) {
|
|
|
+ return { sum, index };
|
|
|
+ }
|
|
|
+
|
|
|
+ const nextSum = sum + value;
|
|
|
+ if (nextSum < regressionStart) {
|
|
|
+ return { sum: nextSum, index };
|
|
|
+ }
|
|
|
+
|
|
|
+ return { sum: nextSum, index: nextIndex };
|
|
|
+ },
|
|
|
+ { sum: 0, index: -1 },
|
|
|
+ );
|
|
|
+
|
|
|
+ if (startIndex === -1) {
|
|
|
+ return cases.map(({ date, value }) => ({
|
|
|
+ date: date.getTime(),
|
|
|
+ value,
|
|
|
+ }));
|
|
|
+ }
|
|
|
+
|
|
|
+ const casesToRegress = cases.slice(startIndex);
|
|
|
+
|
|
|
// It's assumed that the input here is ordered by date ascending
|
|
|
- const minDate = cases[0].date;
|
|
|
+ const minDate = casesToRegress[0].date;
|
|
|
|
|
|
- const xSeries = cases.map(({ date }) => 1 + differenceInDays(date, minDate));
|
|
|
- const ySeries = cases.map(({ value }) => Math.log(value));
|
|
|
+ const xSeries = casesToRegress.map(({ date }) => 1 + differenceInDays(date, minDate));
|
|
|
+ const ySeries = casesToRegress.map(({ value }) => Math.log(value));
|
|
|
|
|
|
const xBar = mean(xSeries);
|
|
|
const yBar = mean(ySeries);
|
|
|
@@ -27,9 +55,15 @@ export function getExponentialRegression(cases: Cases): Data {
|
|
|
const slope = covariance / xVariance;
|
|
|
const intercept = yBar - slope * xBar;
|
|
|
|
|
|
- return cases.map(({ date, value }, index) => ({
|
|
|
- date,
|
|
|
+ const regressionAtDate = (date: Date): number => {
|
|
|
+ const xValue = differenceInDays(date, minDate);
|
|
|
+
|
|
|
+ return Math.exp(slope * xValue + intercept);
|
|
|
+ };
|
|
|
+
|
|
|
+ return cases.map(({ date, value }) => ({
|
|
|
+ date: date.getTime(),
|
|
|
value,
|
|
|
- regression: Math.exp(slope * xSeries[index] + intercept),
|
|
|
+ regression: regressionAtDate(date),
|
|
|
}));
|
|
|
}
|