numz 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +8 -0
- package/demo/__main2.js +49 -0
- package/demo/index.html +25 -0
- package/demo/main.js +4 -0
- package/demo/package-lock.json +852 -0
- package/demo/package.json +14 -0
- package/demo/public/vite.svg +1 -0
- package/demo/src/pages/[blog]/[lang]/index.js +3 -0
- package/demo/src/pages/[blog]/index.js +3 -0
- package/demo/src/pages/about.js +6 -0
- package/demo/src/pages/articles/[data]/[color]/index.js +6 -0
- package/demo/src/pages/articles/a1.js +6 -0
- package/demo/src/pages/index.js +20 -0
- package/demo/src/pages/me.js +3 -0
- package/package.json +34 -0
- package/rollup.config.js +66 -0
- package/src/index.js +1 -0
- package/src/signal/fft/fft1d/index.js +18 -0
- package/src/signal/fft/fftnd/index.js +27 -0
- package/src/signal/fft/index.js +48 -0
- package/src/signal/fft/utils/index.js +19 -0
- package/src/stats/accum/index.js +39 -0
- package/src/stats/average/index.js +75 -0
- package/src/stats/index.js +5 -0
- package/src/stats/percentile/index.js +18 -0
- package/src/stats/rolling/index.js +34 -0
- package/src/stats/variability/index.js +37 -0
- package/src-dep/conv.js +174 -0
- package/src-dep/fft.js +59 -0
- package/src-dep/filter.js +39 -0
- package/src-dep/index.js +85 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { p,App,Flex } from "ziko"
|
|
2
|
+
|
|
3
|
+
const {QueryParams} = __Ziko__
|
|
4
|
+
export default ()=>{
|
|
5
|
+
return App({
|
|
6
|
+
head : {
|
|
7
|
+
title : "ziko",
|
|
8
|
+
},
|
|
9
|
+
wrapper : ()=>Flex(p("Hello world").style({
|
|
10
|
+
color : QueryParams.color ?? "black"
|
|
11
|
+
})).size("100vw","100vh").vertical(0,0)
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
document.body.style.overflow = "hidden"
|
|
15
|
+
// export default ()=>{
|
|
16
|
+
// return p("Hello from zikojs File based routing ").style({
|
|
17
|
+
// color:"red",
|
|
18
|
+
// fontFamily : "Gloria Hallelujah"
|
|
19
|
+
// })
|
|
20
|
+
// }
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "numz",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "scientific computing with zikojs",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports":{
|
|
8
|
+
"./*" : {
|
|
9
|
+
"import" : "./src/*/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
14
|
+
"dev": "cross-env NODE_ENV=development rollup --config rollup.config.js",
|
|
15
|
+
"watch": "cross-env NODE_ENV=development rollup --config rollup.config.js -w",
|
|
16
|
+
"build": "cross-env NODE_ENV=production rollup --config rollup.config.js"
|
|
17
|
+
},
|
|
18
|
+
"author": "zakaria elalaoui",
|
|
19
|
+
"keywords": [
|
|
20
|
+
"zikojs",
|
|
21
|
+
"zikojs-addons"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@rollup/plugin-commonjs": "^28.0.0",
|
|
26
|
+
"@rollup/plugin-node-resolve": "^15.3.0",
|
|
27
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
28
|
+
"cross-env": "^7.0.3",
|
|
29
|
+
"rollup": "^4.24.0"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"ziko": "^0.54.1"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import resolve from "@rollup/plugin-node-resolve";
|
|
2
|
+
import commonjs from '@rollup/plugin-commonjs';
|
|
3
|
+
import terser from "@rollup/plugin-terser";
|
|
4
|
+
|
|
5
|
+
const Addon_name = "ziko-math-signal";
|
|
6
|
+
const NamedExport = "ZMS"
|
|
7
|
+
const Author = "";
|
|
8
|
+
|
|
9
|
+
const banner = `
|
|
10
|
+
/*
|
|
11
|
+
Project: ${Addon_name}
|
|
12
|
+
Author: ${Author}
|
|
13
|
+
Date : ${new Date()}
|
|
14
|
+
*/
|
|
15
|
+
`;
|
|
16
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
17
|
+
|
|
18
|
+
const output = [
|
|
19
|
+
{
|
|
20
|
+
file: `dist/${Addon_name}.mjs`,
|
|
21
|
+
format: "es",
|
|
22
|
+
banner,
|
|
23
|
+
exports: "named",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
file: `dist/${Addon_name}.js`,
|
|
27
|
+
format: "umd",
|
|
28
|
+
name: NamedExport,
|
|
29
|
+
banner,
|
|
30
|
+
exports: "named",
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
isProduction &&
|
|
34
|
+
output.push(
|
|
35
|
+
{
|
|
36
|
+
file: `dist/${Addon_name}.min.mjs`,
|
|
37
|
+
format: "es",
|
|
38
|
+
banner,
|
|
39
|
+
exports: "named",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
file: `dist/${Addon_name}.min.js`,
|
|
43
|
+
format: "umd",
|
|
44
|
+
name: NamedExport,
|
|
45
|
+
banner,
|
|
46
|
+
exports: "named",
|
|
47
|
+
plugins: [
|
|
48
|
+
terser({
|
|
49
|
+
output: {
|
|
50
|
+
comments: (node, { type, value }) =>
|
|
51
|
+
type === "comment2" && value.includes("Author"),
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
export default {
|
|
59
|
+
input: "src/index.js",
|
|
60
|
+
output,
|
|
61
|
+
external: ["ziko"],
|
|
62
|
+
plugins: [
|
|
63
|
+
resolve(),
|
|
64
|
+
commonjs(),
|
|
65
|
+
],
|
|
66
|
+
};
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './stats/index.js'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { twiddle } from "../utils/index.js";
|
|
2
|
+
export function fft1d(arr) {
|
|
3
|
+
const N = arr.length;
|
|
4
|
+
if (N === 1) return [arr[0]];
|
|
5
|
+
|
|
6
|
+
// Split even/odd
|
|
7
|
+
const even = fft1d(arr.filter((_, i) => i % 2 === 0));
|
|
8
|
+
const odd = fft1d(arr.filter((_, i) => i % 2 === 1));
|
|
9
|
+
|
|
10
|
+
const out = new Array(N);
|
|
11
|
+
for (let k = 0; k < N/2; k++) {
|
|
12
|
+
const w = twiddle(N, k);
|
|
13
|
+
const t = w.mul(odd[k]);
|
|
14
|
+
out[k] = even[k].add(t);
|
|
15
|
+
out[k + N/2] = even[k].sub(t);
|
|
16
|
+
}
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { normalizeComplexND } from '../utils/index.js'
|
|
2
|
+
import { fft1d } from '../fft1d/index.js';
|
|
3
|
+
function fftND(arr) {
|
|
4
|
+
arr = normalizeComplexND(arr);
|
|
5
|
+
|
|
6
|
+
// Base case: 1-D
|
|
7
|
+
if (!Array.isArray(arr[0]))
|
|
8
|
+
return fft1d(arr);
|
|
9
|
+
|
|
10
|
+
const transformed = arr.map(sub => fftND(sub));
|
|
11
|
+
|
|
12
|
+
const rows = transformed.length;
|
|
13
|
+
const cols = transformed[0].length;
|
|
14
|
+
|
|
15
|
+
const colsData = Array.from({ length: cols }, (_, c) =>
|
|
16
|
+
Array.from({ length: rows }, (_, r) => transformed[r][c])
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const colsTransformed = colsData.map(col => fft1d(col));
|
|
20
|
+
|
|
21
|
+
// Transpose back
|
|
22
|
+
const out = Array.from({ length: rows }, (_, r) =>
|
|
23
|
+
Array.from({ length: cols }, (_, c) => colsTransformed[c][r])
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
function fft1d(arr) {
|
|
2
|
+
const N = arr.length;
|
|
3
|
+
if (N === 1) return [arr[0]];
|
|
4
|
+
|
|
5
|
+
const even = fft1d(arr.filter((_, i) => i % 2 === 0));
|
|
6
|
+
const odd = fft1d(arr.filter((_, i) => i % 2 === 1));
|
|
7
|
+
|
|
8
|
+
const out = new Array(N);
|
|
9
|
+
for (let k = 0; k < N/2; k++) {
|
|
10
|
+
const t = Complex.Twiddle(N, k).mul(odd[k]);
|
|
11
|
+
out[k] = even[k].add(t);
|
|
12
|
+
out[k + N/2] = even[k].sub(t);
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function fftnd(data) {
|
|
18
|
+
if (data instanceof Matrix) data = data.toComplex();
|
|
19
|
+
|
|
20
|
+
if (Array.isArray(data) && !Array.isArray(data[0])) {
|
|
21
|
+
return fft1d(data);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (data instanceof Matrix) {
|
|
25
|
+
const rows = data.rows;
|
|
26
|
+
const cols = data.cols;
|
|
27
|
+
|
|
28
|
+
// FFT along rows
|
|
29
|
+
let rowFFT = new Matrix(rows, cols, []);
|
|
30
|
+
for (let i = 0; i < rows; i++) {
|
|
31
|
+
rowFFT.arr[i] = fft1d(data.arr[i]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let colFFT = new Matrix(cols, rows, []);
|
|
35
|
+
const rowFFT_T = rowFFT.T;
|
|
36
|
+
for (let i = 0; i < cols; i++) {
|
|
37
|
+
colFFT.arr[i] = fft1d(rowFFT_T.arr[i]);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return colFFT.T;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (Array.isArray(data)) {
|
|
44
|
+
return data.map(fftND);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
throw new Error("Invalid data type for FFT");
|
|
48
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// export const C = (x) => x?.isComplex?.() ? x : new Complex(x, 0);
|
|
2
|
+
// export function twiddle(N, k) {
|
|
3
|
+
// const angle = -2 * Math.PI * k / N;
|
|
4
|
+
// return new Complex(Math.cos(angle), Math.sin(angle));
|
|
5
|
+
// }
|
|
6
|
+
|
|
7
|
+
// function normalizeComplexND(data) {
|
|
8
|
+
// if (data instanceof Matrix) {
|
|
9
|
+
// return new Matrix(
|
|
10
|
+
// data.rows,
|
|
11
|
+
// data.cols,
|
|
12
|
+
// data.arr.flat(1).map(C)
|
|
13
|
+
// );
|
|
14
|
+
// } else if (Array.isArray(data)) {
|
|
15
|
+
// return data.map(normalizeComplexND);
|
|
16
|
+
// } else {
|
|
17
|
+
// return C(data);
|
|
18
|
+
// }
|
|
19
|
+
// }
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const accum_sum = (arr) => {
|
|
2
|
+
let result = [];
|
|
3
|
+
let total = 0;
|
|
4
|
+
for (let x of arr) {
|
|
5
|
+
total += x;
|
|
6
|
+
result.push(total);
|
|
7
|
+
}
|
|
8
|
+
return result;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const accum_product = (arr) => {
|
|
12
|
+
let result = [];
|
|
13
|
+
let prod = 1;
|
|
14
|
+
for (let x of arr) {
|
|
15
|
+
prod *= x;
|
|
16
|
+
result.push(prod);
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const accum_max = (arr) => {
|
|
22
|
+
let result = [];
|
|
23
|
+
let m = -Infinity;
|
|
24
|
+
for (let x of arr) {
|
|
25
|
+
m = Math.max(m, x);
|
|
26
|
+
result.push(m);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const accum_min = (arr) => {
|
|
32
|
+
let result = [];
|
|
33
|
+
let m = Infinity;
|
|
34
|
+
for (let x of arr) {
|
|
35
|
+
m = Math.min(m, x);
|
|
36
|
+
result.push(m);
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Mean
|
|
2
|
+
export const mean = (...x) => x.reduce((a, b) => a + b) / x.length;
|
|
3
|
+
export const geo_mean = (...x) => (x.reduce((a, b) => a * b)) ** (1/x.length);
|
|
4
|
+
// Quadratic Mean
|
|
5
|
+
export const rms = (...x) => {
|
|
6
|
+
const n = x.length;
|
|
7
|
+
return (Math.hypot(...x)/n)**(1/n)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const weighted_mean=(values, weights)=>{
|
|
11
|
+
let sum = 0, sw = 0;
|
|
12
|
+
for (let i = 0; i < values.length; i++) {
|
|
13
|
+
sum += values[i] * weights[i];
|
|
14
|
+
sw += weights[i];
|
|
15
|
+
}
|
|
16
|
+
return sum / sw;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const harmonic_mean = (...x) => {
|
|
20
|
+
let s = 0, i = 0;
|
|
21
|
+
for(i=0; i<x.length; i++)
|
|
22
|
+
s += 1/x[i]
|
|
23
|
+
return x.length / s;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const power_mean = (X, p) =>{
|
|
27
|
+
let s = 0, i = 0, l = X.length;
|
|
28
|
+
for(i=0; i < l; i++)
|
|
29
|
+
s+= X[i]**p
|
|
30
|
+
return (s / l) ** (1 / p);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const trimmed_mean = (X, k) =>{
|
|
34
|
+
let a = [...X].sort((a,b)=>a-b).slice(k, X.length - k);
|
|
35
|
+
return mean(...a);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const winsorized_mean = (X, k) =>{
|
|
39
|
+
let a = [...X].sort((a,b)=>a-b);
|
|
40
|
+
let low = a[k], high = a[a.length - k - 1];
|
|
41
|
+
a = a.map(x => Math.max(low, Math.min(high, x)));
|
|
42
|
+
return mean(a);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const midrange = (x) =>{
|
|
46
|
+
let min = Math.min(...x);
|
|
47
|
+
let max = Math.max(...x);
|
|
48
|
+
return (min + max) / 2;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const midhinge = (...x) =>{
|
|
52
|
+
let a = x.sort((a,b)=>a-b);
|
|
53
|
+
let q1 = a[Math.floor((a.length - 1) * 0.25)];
|
|
54
|
+
let q3 = a[Math.floor((a.length - 1) * 0.75)];
|
|
55
|
+
return (q1 + q3) / 2;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
export const interquartile_mean = (...x) =>{
|
|
60
|
+
let a = x.sort((a,b)=>a-b);
|
|
61
|
+
let q1 = a[Math.floor((a.length - 1) * 0.25)];
|
|
62
|
+
let q3 = a[Math.floor((a.length - 1) * 0.75)];
|
|
63
|
+
let m = a.filter(x => x >= q1 && x <= q3);
|
|
64
|
+
return mean(m);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
export const contraharmonic_mean = (...x) =>{
|
|
69
|
+
let num = 0, den = 0, i, l = x.length;
|
|
70
|
+
for(i = 0; i < l; i++){
|
|
71
|
+
num += x[i]**2;
|
|
72
|
+
den += x[i]
|
|
73
|
+
}
|
|
74
|
+
return num / den;
|
|
75
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const percentile = (X, p) => {
|
|
2
|
+
if (X.length === 0)
|
|
3
|
+
return NaN;
|
|
4
|
+
let a = X.sort((x, y) => x - y);
|
|
5
|
+
let index = (p / 100) * (a.length - 1);
|
|
6
|
+
let i = Math.floor(index);
|
|
7
|
+
let f = index - i;
|
|
8
|
+
if (i === a.length - 1)
|
|
9
|
+
return a[i];
|
|
10
|
+
return a[i] * (1 - f) + a[i + 1] * f;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const q1 = X => percentile(X, 25);
|
|
14
|
+
export const median = X => percentile(X, 50);
|
|
15
|
+
export const q3 = X => percentile(X, 75);
|
|
16
|
+
|
|
17
|
+
// Interquartile Range
|
|
18
|
+
export const iqr = X => q3(X) - q1(X)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Simple Moving Average
|
|
2
|
+
export const sma = (X, w) =>{
|
|
3
|
+
let r = [];
|
|
4
|
+
for (let i = 0; i <= X.length - w; i++) {
|
|
5
|
+
let s = 0;
|
|
6
|
+
for (let j = 0; j < w; j++) s += X[i + j];
|
|
7
|
+
r.push(s / w);
|
|
8
|
+
}
|
|
9
|
+
return r;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// exponential Moving Average
|
|
13
|
+
export const ema = (X, alpha) =>{
|
|
14
|
+
let r = [], prev = X[0];
|
|
15
|
+
r.push(prev);
|
|
16
|
+
for (let i = 1; i < X.length; i++) {
|
|
17
|
+
prev = alpha * X[i] + (1 - alpha) * prev;
|
|
18
|
+
r.push(prev);
|
|
19
|
+
}
|
|
20
|
+
return r;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// weightedMovingAverage
|
|
24
|
+
export const wma = (X, weights) =>{
|
|
25
|
+
let k = weights.length;
|
|
26
|
+
let sw = weights.reduce((a,b)=>a+b, 0);
|
|
27
|
+
let r = [];
|
|
28
|
+
for (let i = 0; i <= X.length - k; i++) {
|
|
29
|
+
let s = 0;
|
|
30
|
+
for (let j = 0; j < k; j++) s += X[i+j] * weights[j];
|
|
31
|
+
r.push(s / sw);
|
|
32
|
+
}
|
|
33
|
+
return r;
|
|
34
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Population Variance
|
|
2
|
+
import { mean } from "../average/index.js";
|
|
3
|
+
export const variance = (...x) => {
|
|
4
|
+
const n = x.length;
|
|
5
|
+
if (n === 0) return NaN;
|
|
6
|
+
const x_mean = mean(...x);
|
|
7
|
+
return x.reduce((sum, xi) => sum + (xi - x_mean) ** 2, 0) / n;
|
|
8
|
+
};
|
|
9
|
+
export const std = (...x) => Math.sqrt(variance(...x));
|
|
10
|
+
|
|
11
|
+
export const sample_variance = (...x) => {
|
|
12
|
+
const n = x.length;
|
|
13
|
+
if (n < 2) return NaN;
|
|
14
|
+
const x_mean = mean(...x);
|
|
15
|
+
return x.reduce((sum, xi) => sum + (xi - x_mean) ** 2, 0) / (n - 1);
|
|
16
|
+
};
|
|
17
|
+
export const sample_std = (...x) => Math.sqrt(sample_variance(...x));
|
|
18
|
+
|
|
19
|
+
export const weighted_variance = (X, weights) => {
|
|
20
|
+
const n = X.length;
|
|
21
|
+
if (n === 0 || weights.length !== n) return NaN;
|
|
22
|
+
const sw = weights.reduce((sum, w) => sum + w, 0);
|
|
23
|
+
const mean = X.reduce((sum, x, i) => sum + x * weights[i], 0) / sw;
|
|
24
|
+
return X.reduce((sum, x, i) => sum + weights[i] * (x - mean) ** 2, 0) / sw;
|
|
25
|
+
};
|
|
26
|
+
export const weighted_std = (X, weights) => Math.sqrt(weighted_variance(X, weights));
|
|
27
|
+
|
|
28
|
+
export const rolling_variance = (X, windowSize) => {
|
|
29
|
+
if (windowSize < 1 || X.length < windowSize) return [];
|
|
30
|
+
let result = [];
|
|
31
|
+
for (let i = 0; i <= X.length - windowSize; i++) {
|
|
32
|
+
const w = X.slice(i, i + windowSize);
|
|
33
|
+
result.push(sample_variance(w)); // usually sample variance for rolling
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
export const rolling_std = (X, windowSize) => Math.sqrt(rolling_variance(X, windowSize));
|