OLD | NEW |
(Empty) | |
| 1 'use strict'; |
| 2 |
| 3 (function(exports) { |
| 4 |
| 5 var rank = { |
| 6 /* |
| 7 * Standart ranking |
| 8 * |
| 9 * The MIT License, Copyright (c) 2014 Ben Magyar |
| 10 */ |
| 11 standard: function(array, key) { |
| 12 // sort the array |
| 13 array = array.sort(function(a, b) { |
| 14 var x = a[key]; |
| 15 var y = b[key]; |
| 16 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); |
| 17 }); |
| 18 // assign a naive ranking |
| 19 for (var i = 1; i < array.length + 1; i++) { |
| 20 array[i - 1]['rank'] = i; |
| 21 } |
| 22 return array; |
| 23 }, |
| 24 /* |
| 25 * Fractional ranking |
| 26 * |
| 27 * The MIT License, Copyright (c) 2014 Ben Magyar |
| 28 */ |
| 29 fractional: function(array, key) { |
| 30 array = this.standard(array, key); |
| 31 // now apply fractional |
| 32 var pos = 0; |
| 33 while (pos < array.length) { |
| 34 var sum = 0; |
| 35 var i = 0; |
| 36 for (i = 0; array[pos + i + 1] && (array[pos + i][key] === array
[pos + i + 1][key]); i++) { |
| 37 sum += array[pos + i]['rank']; |
| 38 } |
| 39 sum += array[pos + i]['rank']; |
| 40 var endPos = pos + i + 1; |
| 41 for (pos; pos < endPos; pos++) { |
| 42 array[pos]['rank'] = sum / (i + 1); |
| 43 } |
| 44 pos = endPos; |
| 45 } |
| 46 return array; |
| 47 }, |
| 48 rank: function(x, y) { |
| 49 var nx = x.length, |
| 50 ny = y.length, |
| 51 combined = [], |
| 52 ranked; |
| 53 while (nx--) { |
| 54 combined.push({ |
| 55 set: 'x', |
| 56 val: x[nx] |
| 57 }); |
| 58 } |
| 59 while (ny--) { |
| 60 combined.push({ |
| 61 set: 'y', |
| 62 val: y[ny] |
| 63 }); |
| 64 } |
| 65 ranked = this.fractional(combined, 'val'); |
| 66 return ranked |
| 67 } |
| 68 }; |
| 69 |
| 70 /* |
| 71 * Error function |
| 72 * |
| 73 * The MIT License, Copyright (c) 2013 jStat |
| 74 */ |
| 75 var erf = function erf(x) { |
| 76 var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.947647320418583
6e-2, -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4, |
| 77 4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6, |
| 78 1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8, |
| 79 6.529054439e-9, 5.059343495e-9, -9.91364156e-10, -2.27365122e-10, 9.
6467911e-11, 2.394038e-12, -6.886027e-12, 8.94487e-13, 3.13092e-13, -1.12708e-13
, 3.81e-16, 7.106e-15, -1.523e-15, -9.4e-17, 1.21e-16, -2.8e-17 |
| 80 ]; |
| 81 var j = cof.length - 1; |
| 82 var isneg = false; |
| 83 var d = 0; |
| 84 var dd = 0; |
| 85 var t, ty, tmp, res; |
| 86 |
| 87 if (x < 0) { |
| 88 x = -x; |
| 89 isneg = true; |
| 90 } |
| 91 |
| 92 t = 2 / (2 + x); |
| 93 ty = 4 * t - 2; |
| 94 |
| 95 for (; j > 0; j--) { |
| 96 tmp = d; |
| 97 d = ty * d - dd + cof[j]; |
| 98 dd = tmp; |
| 99 } |
| 100 |
| 101 res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd); |
| 102 return isneg ? res - 1 : 1 - res; |
| 103 }; |
| 104 |
| 105 /* |
| 106 * Normal distribution CDF |
| 107 * |
| 108 * The MIT License, Copyright (c) 2013 jStat |
| 109 */ |
| 110 var dnorm = function(x, mean, std) { |
| 111 return 0.5 * (1 + erf((x - mean) / Math.sqrt(2 * std * std))); |
| 112 } |
| 113 |
| 114 var statistic = function(x, y) { |
| 115 var ranked = rank.rank(x, y), |
| 116 nr = ranked.length, |
| 117 nx = x.length, |
| 118 ny = y.length, |
| 119 ranksums = { |
| 120 x: 0, |
| 121 y: 0 |
| 122 }, |
| 123 i = 0, t = 0, nt = 1, tcf, ux, uy; |
| 124 |
| 125 while (i < nr) { |
| 126 if (i > 0) { |
| 127 if (ranked[i].val == ranked[i-1].val) { |
| 128 nt++; |
| 129 } else { |
| 130 if (nt > 1) { |
| 131 t += Math.pow(nt, 3) - nt |
| 132 nt = 1; |
| 133 } |
| 134 } |
| 135 } |
| 136 ranksums[ranked[i].set] += ranked[i].rank |
| 137 i++; |
| 138 } |
| 139 tcf = 1 - (t / (Math.pow(nr, 3) - nr)) |
| 140 ux = nx*ny + (nx*(nx+1)/2) - ranksums.x; |
| 141 uy = nx*ny - ux; |
| 142 |
| 143 return { |
| 144 tcf: tcf, |
| 145 ux: ux, |
| 146 uy: uy, |
| 147 big: Math.max(ux, uy), |
| 148 small: Math.min(ux, uy) |
| 149 } |
| 150 } |
| 151 |
| 152 exports.test = function(x, y, alt, corr) { |
| 153 // set default value for alternative |
| 154 alt = typeof alt !== 'undefined' ? alt : 'two-sided'; |
| 155 // set default value for continuity |
| 156 corr = typeof corr !== 'undefined' ? corr : true; |
| 157 var nx = x.length, // x's size |
| 158 ny = y.length, // y's size |
| 159 f = 1, |
| 160 u, mu, std, z, p; |
| 161 |
| 162 // test statistic |
| 163 u = statistic(x, y); |
| 164 |
| 165 // mean compute and correct if given |
| 166 if (corr) { |
| 167 mu = (nx * ny / 2) + 0.5; |
| 168 } else { |
| 169 mu = nx * ny / 2; |
| 170 } |
| 171 |
| 172 // compute standard deviation using tie correction factor |
| 173 std = Math.sqrt(u.tcf * nx * ny * (nx + ny + 1) / 12); |
| 174 |
| 175 // compute z according to given alternative |
| 176 if (alt == 'less') { |
| 177 z = (u.ux - mu) / std; |
| 178 } else if (alt == 'greater') { |
| 179 z = (u.uy - mu) / std; |
| 180 } else if (alt == 'two-sided') { |
| 181 z = Math.abs((u.big - mu) / std); |
| 182 } else { |
| 183 console.log('Unknown alternative argument'); |
| 184 } |
| 185 |
| 186 // factor to correct two sided p-value |
| 187 if (alt == 'two-sided') { |
| 188 f = 2; |
| 189 } |
| 190 |
| 191 // compute p-value using CDF of standard normal |
| 192 p = dnorm(-z, 0, 1) * f; |
| 193 |
| 194 return {U: u.small, p: p}; |
| 195 } |
| 196 |
| 197 })(typeof exports === 'undefined' ? this['mannwhitneyu'] = {} : exports); |
OLD | NEW |