tweak: use lerna
This commit is contained in:
parent
803860ec27
commit
c5c34e0171
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,3 +0,0 @@
|
|||
[submodule "src/aggregation"]
|
||||
path = src/aggregation
|
||||
url = ./src/aggregation/
|
2
index.js
2
index.js
|
@ -5,7 +5,7 @@ import {
|
|||
geometricMeanOfOdds,
|
||||
extremizedGeometricMeanOfOdds,
|
||||
neyman,
|
||||
} from "./src/aggregation/index.js";
|
||||
} from "./packages/aggregation";
|
||||
|
||||
export {
|
||||
median,
|
||||
|
|
6
lerna.json
Normal file
6
lerna.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "independent"
|
||||
}
|
|
@ -14,5 +14,8 @@
|
|||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@forecasting/aggregation": "^0.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lerna": "^4.0.0"
|
||||
}
|
||||
}
|
||||
|
|
76
packages/aggregation/README.md
Normal file
76
packages/aggregation/README.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
## About
|
||||
|
||||
![](decision-method.png)
|
||||
|
||||
This package contains a series of utilities for forecast aggregation. It is currently in _alpha_, meaning that the code hasn't been tested much.
|
||||
|
||||
For an introduction to different aggregation methods, see Jaime Sevilla's [Aggregation](https://forum.effectivealtruism.org/s/hjiBqAJNKhfJFq7kf) series. For an explanation of the neyman method, see [here](https://forum.effectivealtruism.org/s/hjiBqAJNKhfJFq7kf/p/biL94PKfeHmgHY6qe).
|
||||
|
||||
## Built with
|
||||
|
||||
- vanilla javascript
|
||||
- [Best readme template](https://github.com/othneildrew/Best-README-Template)
|
||||
|
||||
## Getting started
|
||||
|
||||
### Installation
|
||||
|
||||
```sh
|
||||
npm install @forecasting/aggregation
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```js
|
||||
import {
|
||||
median,
|
||||
arithmeticMean,
|
||||
geometricMean,
|
||||
geometricMeanOfOdds,
|
||||
extremizedGeometricMeanOfOdds,
|
||||
neyman,
|
||||
} from "@forecasting/aggregation";
|
||||
|
||||
let ps = [0.1, 0.2, 0.4, 0.5];
|
||||
console.log(ps);
|
||||
|
||||
console.log(median(ps));
|
||||
console.log(arithmeticMean(ps));
|
||||
console.log(geometricMean(ps));
|
||||
console.log(geometricMeanOfOdds(ps));
|
||||
console.log(extremizedGeometricMeanOfOdds(ps, 1.5)); // 1.5 is the extremization factor
|
||||
console.log(extremizedGeometricMeanOfOdds(ps, 2.5));
|
||||
console.log(neyman(ps));
|
||||
|
||||
// invalid inputs, will return -1
|
||||
let notArrayOfProbabilities0 = "Hello world!";
|
||||
console.log(arithmeticMean(notArrayOfProbabilities0)); // -1
|
||||
let notArrayOfProbabilities1 = [];
|
||||
console.log(arithmeticMean(notArrayOfProbabilities1)); // -1
|
||||
let notArrayOfProbabilities2 = ["a"];
|
||||
console.log(arithmeticMean(notArrayOfProbabilities2)); // -1
|
||||
let notArrayOfProbabilities3 = [2, 4, 5];
|
||||
console.log(arithmeticMean(notArrayOfProbabilities3)); // -1
|
||||
let notArrayOfProbabilities4 = [0.2, 4, 5];
|
||||
console.log(arithmeticMean(notArrayOfProbabilities4)); // -1
|
||||
|
||||
const chosenAggregationMethod = neyman;
|
||||
const getAggregatedProbabilities = (array) => {
|
||||
let result = neyman(array);
|
||||
if (result == -1) {
|
||||
// handle case somehow; maybe throw an error, e.g.:
|
||||
// throw new Error("Invalid array of probabilities")
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
- [x] validate probability (must be 0<= p <=1)
|
||||
- [x] Decide on a return type if probabilities are not validated (-1? / null?)
|
||||
- [x] Write wrapper code for validation
|
||||
- [x] Validate that array.length > 0
|
||||
- [ ] add weighting? by recency?
|
||||
- [ ] filter outliers?
|
BIN
packages/aggregation/decision-method.png
Normal file
BIN
packages/aggregation/decision-method.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 232 KiB |
74
packages/aggregation/index.js
Normal file
74
packages/aggregation/index.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Helpers
|
||||
const sum = (array) => array.reduce((a, b) => a + b, 0);
|
||||
const probabilityToOdds = (p) => p / (1 - p);
|
||||
const oddsToProbability = (o) => o / (1 + o);
|
||||
const validateArray = (arr) =>
|
||||
Array.isArray(arr) &&
|
||||
arr.length > 0 &&
|
||||
arr.reduce((a, b) => a && typeof b == "number" && b >= 0 && b <= 1, true);
|
||||
|
||||
// Main functions
|
||||
export const median = (array) => {
|
||||
if (!validateArray(array)) return -1;
|
||||
// needs validation array not empty
|
||||
let midway = Math.floor(array.length) / 2;
|
||||
let arrayToBeSorted = [...array];
|
||||
// sorting mutates the array, which I am averse to
|
||||
let arraySorted = arrayToBeSorted.sort((a, b) => a - b);
|
||||
if (midway % 2) {
|
||||
return arraySorted[midway];
|
||||
} else {
|
||||
return (arraySorted[midway - 1] + arraySorted[midway]) / 2;
|
||||
}
|
||||
};
|
||||
|
||||
export const arithmeticMean = (array) => {
|
||||
if (!validateArray(array)) return -1;
|
||||
let result = sum(array) / array.length;
|
||||
return result;
|
||||
};
|
||||
|
||||
export const geometricMean = (array) => {
|
||||
if (!validateArray(array)) return -1;
|
||||
// sum of logs seems more numerically stable than multiplying a lot of numbers 0<=p<=1
|
||||
let arrayAsLog = array.map((p) => Math.log(p));
|
||||
let sumOfLogs = sum(arrayAsLog) / arrayAsLog.length;
|
||||
let result = Math.exp(sumOfLogs);
|
||||
return result;
|
||||
};
|
||||
|
||||
export const geometricMeanOfOdds = (array) => {
|
||||
if (!validateArray(array)) return -1;
|
||||
let arrayOfOdds = array.map((p) => probabilityToOdds(p));
|
||||
let arrayOfLogsOfOdds = arrayOfOdds.map((p) => Math.log(p));
|
||||
let sumOfLogsOfOdds = sum(arrayOfLogsOfOdds) / arrayOfLogsOfOdds.length;
|
||||
let geomMeanOfOdds = Math.exp(sumOfLogsOfOdds);
|
||||
let result = oddsToProbability(geomMeanOfOdds);
|
||||
return result;
|
||||
};
|
||||
|
||||
export const extremizedGeometricMeanOfOdds = (
|
||||
array,
|
||||
extremizationParameter = 1.5
|
||||
) => {
|
||||
if (!validateArray(array)) return -1;
|
||||
let arrayOfOdds = array.map((p) => probabilityToOdds(p));
|
||||
let arrayOfLogsOfOdds = arrayOfOdds.map((p) => Math.log(p));
|
||||
let extremizedSumOfLogsOfOdds =
|
||||
(extremizationParameter * sum(arrayOfLogsOfOdds)) /
|
||||
arrayOfLogsOfOdds.length;
|
||||
let extremizedGeomMeanOfOdds = Math.exp(extremizedSumOfLogsOfOdds);
|
||||
let result = oddsToProbability(extremizedGeomMeanOfOdds);
|
||||
return result;
|
||||
};
|
||||
|
||||
export const neyman = (array) => {
|
||||
if (!validateArray(array)) return -1;
|
||||
let n = array.length;
|
||||
|
||||
let d =
|
||||
(n * (Math.sqrt(3 * Math.pow(n, 2) - 3 * n + 1) - 2)) /
|
||||
(Math.pow(n, 2) - n - 1);
|
||||
let result = extremizedGeometricMeanOfOdds(array, d);
|
||||
return result;
|
||||
};
|
19
packages/aggregation/package.json
Normal file
19
packages/aggregation/package.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "@forecasting/aggregation",
|
||||
"version": "1.0.1",
|
||||
"description": "Forecasting aggregation utilities",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "node tests.js"
|
||||
},
|
||||
"keywords": [
|
||||
"forecasting",
|
||||
"aggregation",
|
||||
"prediction",
|
||||
"prediction",
|
||||
"markets"
|
||||
],
|
||||
"type": "module",
|
||||
"author": "Nuño Sempere",
|
||||
"license": "MIT"
|
||||
}
|
31
packages/aggregation/tests.js
Normal file
31
packages/aggregation/tests.js
Normal file
|
@ -0,0 +1,31 @@
|
|||
import {
|
||||
median,
|
||||
arithmeticMean,
|
||||
geometricMean,
|
||||
geometricMeanOfOdds,
|
||||
extremizedGeometricMeanOfOdds,
|
||||
neyman,
|
||||
} from "./index.js";
|
||||
|
||||
let ps = [0.1, 0.2, 0.4, 0.5];
|
||||
console.log(ps);
|
||||
|
||||
console.log(median(ps));
|
||||
console.log(arithmeticMean(ps));
|
||||
console.log(geometricMean(ps));
|
||||
console.log(geometricMeanOfOdds(ps));
|
||||
console.log(extremizedGeometricMeanOfOdds(ps, 1.5));
|
||||
console.log(extremizedGeometricMeanOfOdds(ps, 2.5));
|
||||
console.log(neyman(ps));
|
||||
|
||||
// invalid inputs, will return -1
|
||||
let notArrayOfProbabilities0 = "Hello world!";
|
||||
console.log(arithmeticMean(notArrayOfProbabilities0)); // -1
|
||||
let notArrayOfProbabilities1 = [];
|
||||
console.log(arithmeticMean(notArrayOfProbabilities1)); // -1
|
||||
let notArrayOfProbabilities2 = ["a"];
|
||||
console.log(arithmeticMean(notArrayOfProbabilities2)); // -1
|
||||
let notArrayOfProbabilities3 = [2, 4, 5];
|
||||
console.log(arithmeticMean(notArrayOfProbabilities3)); // -1
|
||||
let notArrayOfProbabilities4 = [0.2, 4, 5];
|
||||
console.log(arithmeticMean(notArrayOfProbabilities4)); // -1
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 359897cc5221b0f6ee2f428484daa05253a94364
|
Loading…
Reference in New Issue
Block a user