-
Notifications
You must be signed in to change notification settings - Fork 2
/
spearman-rho.js
107 lines (87 loc) · 2.52 KB
/
spearman-rho.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"use strict";
const _ = require('lodash');
/* Spearman's rank correlation coefficient */
/* https://de.wikipedia.org/wiki/Rangkorrelationskoeffizient */
class SpearmanRHO {
constructor(X, Y) {
if (X.length !== Y.length) {
throw new Error('Datasets do not have the same length.');
}
this.X = X;
this.Y = Y;
this.n = X.length = Y.length;
}
prepare(values) {
return new Promise(function (resolve, reject) {
resolve(_.map(values, (value, index) => {
return {
index: index++,
value: value,
rank: 0
};
}));
});
}
addRank(values) {
return new Promise(function (resolve, reject) {
const rank = _.chain(values)
.sortBy('value')
.map((value, index) => _.set(value, 'rank', index++))
.value();
resolve(rank);
});
}
standardizeRank(timeSeries) {
return new Promise(function (resolve, reject) {
const rank = _.chain(timeSeries)
.groupBy('value')
.map(groupValues => {
const groupMean = _.meanBy(groupValues, 'rank');
return _.map(groupValues, value =>
_.set(value, 'rank', groupMean)
);
})
.flatten()
.sortBy('index')
.value();
resolve(rank);
});
}
Ed_2(X, Y) {
return _.chain(this.n)
.times(i => Math.pow(X[i].rank - Y[i].rank, 2))
.sum()
.value();
}
T_(values) {
return _.chain(values)
.groupBy('rank')
.map(value => _.toInteger(value.length))
.sumBy(value => Math.pow(value, 3) - value)
.value();
}
calc() {
return new Promise((resolve, reject) => {
Promise.all([
this.prepare(this.X)
.then(X => this.addRank(X))
.then(X => this.standardizeRank(X)),
this.prepare(this.Y)
.then(Y => this.addRank(Y))
.then(Y => this.standardizeRank(Y))
]).then(values => {
const X = values[0];
const Y = values[1];
Promise.all([this.T_(X), this.T_(Y)])
.then(values => {
const Tx = values[0];
const Ty = values[1];
const numerator = Math.pow(this.n, 3) - this.n - 0.5 * Tx - 0.5 * Ty - 6 * this.Ed_2(X, Y);
const denominator = (Math.pow(this.n, 3) - this.n - Tx) * (Math.pow(this.n, 3) - this.n - Ty);
resolve(denominator <= 0 ? 0 : (numerator / Math.sqrt(denominator)));
}).catch(err => console.error(err));
}).catch(err => console.error(err));
});
}
}
module.exports = SpearmanRHO;