340 lines
9.6 KiB
JavaScript
340 lines
9.6 KiB
JavaScript
(function(jStat, Math) {
|
|
|
|
var slice = [].slice;
|
|
var isNumber = jStat.utils.isNumber;
|
|
var isArray = jStat.utils.isArray;
|
|
|
|
// flag==true denotes use of sample standard deviation
|
|
// Z Statistics
|
|
jStat.extend({
|
|
// 2 different parameter lists:
|
|
// (value, mean, sd)
|
|
// (value, array, flag)
|
|
zscore: function zscore() {
|
|
var args = slice.call(arguments);
|
|
if (isNumber(args[1])) {
|
|
return (args[0] - args[1]) / args[2];
|
|
}
|
|
return (args[0] - jStat.mean(args[1])) / jStat.stdev(args[1], args[2]);
|
|
},
|
|
|
|
// 3 different paramter lists:
|
|
// (value, mean, sd, sides)
|
|
// (zscore, sides)
|
|
// (value, array, sides, flag)
|
|
ztest: function ztest() {
|
|
var args = slice.call(arguments);
|
|
var z;
|
|
if (isArray(args[1])) {
|
|
// (value, array, sides, flag)
|
|
z = jStat.zscore(args[0],args[1],args[3]);
|
|
return (args[2] === 1) ?
|
|
(jStat.normal.cdf(-Math.abs(z), 0, 1)) :
|
|
(jStat.normal.cdf(-Math.abs(z), 0, 1)*2);
|
|
} else {
|
|
if (args.length > 2) {
|
|
// (value, mean, sd, sides)
|
|
z = jStat.zscore(args[0],args[1],args[2]);
|
|
return (args[3] === 1) ?
|
|
(jStat.normal.cdf(-Math.abs(z),0,1)) :
|
|
(jStat.normal.cdf(-Math.abs(z),0,1)* 2);
|
|
} else {
|
|
// (zscore, sides)
|
|
z = args[0];
|
|
return (args[1] === 1) ?
|
|
(jStat.normal.cdf(-Math.abs(z),0,1)) :
|
|
(jStat.normal.cdf(-Math.abs(z),0,1)*2);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
jStat.extend(jStat.fn, {
|
|
zscore: function zscore(value, flag) {
|
|
return (value - this.mean()) / this.stdev(flag);
|
|
},
|
|
|
|
ztest: function ztest(value, sides, flag) {
|
|
var zscore = Math.abs(this.zscore(value, flag));
|
|
return (sides === 1) ?
|
|
(jStat.normal.cdf(-zscore, 0, 1)) :
|
|
(jStat.normal.cdf(-zscore, 0, 1) * 2);
|
|
}
|
|
});
|
|
|
|
// T Statistics
|
|
jStat.extend({
|
|
// 2 parameter lists
|
|
// (value, mean, sd, n)
|
|
// (value, array)
|
|
tscore: function tscore() {
|
|
var args = slice.call(arguments);
|
|
return (args.length === 4) ?
|
|
((args[0] - args[1]) / (args[2] / Math.sqrt(args[3]))) :
|
|
((args[0] - jStat.mean(args[1])) /
|
|
(jStat.stdev(args[1], true) / Math.sqrt(args[1].length)));
|
|
},
|
|
|
|
// 3 different paramter lists:
|
|
// (value, mean, sd, n, sides)
|
|
// (tscore, n, sides)
|
|
// (value, array, sides)
|
|
ttest: function ttest() {
|
|
var args = slice.call(arguments);
|
|
var tscore;
|
|
if (args.length === 5) {
|
|
tscore = Math.abs(jStat.tscore(args[0], args[1], args[2], args[3]));
|
|
return (args[4] === 1) ?
|
|
(jStat.studentt.cdf(-tscore, args[3]-1)) :
|
|
(jStat.studentt.cdf(-tscore, args[3]-1)*2);
|
|
}
|
|
if (isNumber(args[1])) {
|
|
tscore = Math.abs(args[0])
|
|
return (args[2] == 1) ?
|
|
(jStat.studentt.cdf(-tscore, args[1]-1)) :
|
|
(jStat.studentt.cdf(-tscore, args[1]-1) * 2);
|
|
}
|
|
tscore = Math.abs(jStat.tscore(args[0], args[1]))
|
|
return (args[2] == 1) ?
|
|
(jStat.studentt.cdf(-tscore, args[1].length-1)) :
|
|
(jStat.studentt.cdf(-tscore, args[1].length-1) * 2);
|
|
}
|
|
});
|
|
|
|
jStat.extend(jStat.fn, {
|
|
tscore: function tscore(value) {
|
|
return (value - this.mean()) / (this.stdev(true) / Math.sqrt(this.cols()));
|
|
},
|
|
|
|
ttest: function ttest(value, sides) {
|
|
return (sides === 1) ?
|
|
(1 - jStat.studentt.cdf(Math.abs(this.tscore(value)), this.cols()-1)) :
|
|
(jStat.studentt.cdf(-Math.abs(this.tscore(value)), this.cols()-1)*2);
|
|
}
|
|
});
|
|
|
|
// F Statistics
|
|
jStat.extend({
|
|
// Paramter list is as follows:
|
|
// (array1, array2, array3, ...)
|
|
// or it is an array of arrays
|
|
// array of arrays conversion
|
|
anovafscore: function anovafscore() {
|
|
var args = slice.call(arguments),
|
|
expVar, sample, sampMean, sampSampMean, tmpargs, unexpVar, i, j;
|
|
if (args.length === 1) {
|
|
tmpargs = new Array(args[0].length);
|
|
for (i = 0; i < args[0].length; i++) {
|
|
tmpargs[i] = args[0][i];
|
|
}
|
|
args = tmpargs;
|
|
}
|
|
// Builds sample array
|
|
sample = new Array();
|
|
for (i = 0; i < args.length; i++) {
|
|
sample = sample.concat(args[i]);
|
|
}
|
|
sampMean = jStat.mean(sample);
|
|
// Computes the explained variance
|
|
expVar = 0;
|
|
for (i = 0; i < args.length; i++) {
|
|
expVar = expVar + args[i].length * Math.pow(jStat.mean(args[i]) - sampMean, 2);
|
|
}
|
|
expVar /= (args.length - 1);
|
|
// Computes unexplained variance
|
|
unexpVar = 0;
|
|
for (i = 0; i < args.length; i++) {
|
|
sampSampMean = jStat.mean(args[i]);
|
|
for (j = 0; j < args[i].length; j++) {
|
|
unexpVar += Math.pow(args[i][j] - sampSampMean, 2);
|
|
}
|
|
}
|
|
unexpVar /= (sample.length - args.length);
|
|
return expVar / unexpVar;
|
|
},
|
|
|
|
// 2 different paramter setups
|
|
// (array1, array2, array3, ...)
|
|
// (anovafscore, df1, df2)
|
|
anovaftest: function anovaftest() {
|
|
var args = slice.call(arguments),
|
|
df1, df2, n, i;
|
|
if (isNumber(args[0])) {
|
|
return 1 - jStat.centralF.cdf(args[0], args[1], args[2]);
|
|
}
|
|
var anovafscore = jStat.anovafscore(args);
|
|
df1 = args.length - 1;
|
|
n = 0;
|
|
for (i = 0; i < args.length; i++) {
|
|
n = n + args[i].length;
|
|
}
|
|
df2 = n - df1 - 1;
|
|
return 1 - jStat.centralF.cdf(anovafscore, df1, df2);
|
|
},
|
|
|
|
ftest: function ftest(fscore, df1, df2) {
|
|
return 1 - jStat.centralF.cdf(fscore, df1, df2);
|
|
}
|
|
});
|
|
|
|
jStat.extend(jStat.fn, {
|
|
anovafscore: function anovafscore() {
|
|
return jStat.anovafscore(this.toArray());
|
|
},
|
|
|
|
anovaftes: function anovaftes() {
|
|
var n = 0;
|
|
var i;
|
|
for (i = 0; i < this.length; i++) {
|
|
n = n + this[i].length;
|
|
}
|
|
return jStat.ftest(this.anovafscore(), this.length - 1, n - this.length);
|
|
}
|
|
});
|
|
|
|
// Tukey's range test
|
|
jStat.extend({
|
|
// 2 parameter lists
|
|
// (mean1, mean2, n1, n2, sd)
|
|
// (array1, array2, sd)
|
|
qscore: function qscore() {
|
|
var args = slice.call(arguments);
|
|
var mean1, mean2, n1, n2, sd;
|
|
if (isNumber(args[0])) {
|
|
mean1 = args[0];
|
|
mean2 = args[1];
|
|
n1 = args[2];
|
|
n2 = args[3];
|
|
sd = args[4];
|
|
} else {
|
|
mean1 = jStat.mean(args[0]);
|
|
mean2 = jStat.mean(args[1]);
|
|
n1 = args[0].length;
|
|
n2 = args[1].length;
|
|
sd = args[2];
|
|
}
|
|
return Math.abs(mean1 - mean2) / (sd * Math.sqrt((1 / n1 + 1 / n2) / 2));
|
|
},
|
|
|
|
// 3 different parameter lists:
|
|
// (qscore, n, k)
|
|
// (mean1, mean2, n1, n2, sd, n, k)
|
|
// (array1, array2, sd, n, k)
|
|
qtest: function qtest() {
|
|
var args = slice.call(arguments);
|
|
|
|
var qscore;
|
|
if (args.length === 3) {
|
|
qscore = args[0];
|
|
args = args.slice(1);
|
|
} else if (args.length === 7) {
|
|
qscore = jStat.qscore(args[0], args[1], args[2], args[3], args[4]);
|
|
args = args.slice(5);
|
|
} else {
|
|
qscore = jStat.qscore(args[0], args[1], args[2]);
|
|
args = args.slice(3);
|
|
}
|
|
|
|
var n = args[0];
|
|
var k = args[1];
|
|
|
|
return 1 - jStat.tukey.cdf(qscore, k, n - k);
|
|
},
|
|
|
|
tukeyhsd: function tukeyhsd(arrays) {
|
|
var sd = jStat.pooledstdev(arrays);
|
|
var means = arrays.map(function (arr) {return jStat.mean(arr);});
|
|
var n = arrays.reduce(function (n, arr) {return n + arr.length;}, 0);
|
|
|
|
var results = [];
|
|
for (var i = 0; i < arrays.length; ++i) {
|
|
for (var j = i + 1; j < arrays.length; ++j) {
|
|
var p = jStat.qtest(means[i], means[j], arrays[i].length, arrays[j].length, sd, n, arrays.length);
|
|
results.push([[i, j], p]);
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
});
|
|
|
|
// Error Bounds
|
|
jStat.extend({
|
|
// 2 different parameter setups
|
|
// (value, alpha, sd, n)
|
|
// (value, alpha, array)
|
|
normalci: function normalci() {
|
|
var args = slice.call(arguments),
|
|
ans = new Array(2),
|
|
change;
|
|
if (args.length === 4) {
|
|
change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) *
|
|
args[2] / Math.sqrt(args[3]));
|
|
} else {
|
|
change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) *
|
|
jStat.stdev(args[2]) / Math.sqrt(args[2].length));
|
|
}
|
|
ans[0] = args[0] - change;
|
|
ans[1] = args[0] + change;
|
|
return ans;
|
|
},
|
|
|
|
// 2 different parameter setups
|
|
// (value, alpha, sd, n)
|
|
// (value, alpha, array)
|
|
tci: function tci() {
|
|
var args = slice.call(arguments),
|
|
ans = new Array(2),
|
|
change;
|
|
if (args.length === 4) {
|
|
change = Math.abs(jStat.studentt.inv(args[1] / 2, args[3] - 1) *
|
|
args[2] / Math.sqrt(args[3]));
|
|
} else {
|
|
change = Math.abs(jStat.studentt.inv(args[1] / 2, args[2].length - 1) *
|
|
jStat.stdev(args[2], true) / Math.sqrt(args[2].length));
|
|
}
|
|
ans[0] = args[0] - change;
|
|
ans[1] = args[0] + change;
|
|
return ans;
|
|
},
|
|
|
|
significant: function significant(pvalue, alpha) {
|
|
return pvalue < alpha;
|
|
}
|
|
});
|
|
|
|
jStat.extend(jStat.fn, {
|
|
normalci: function normalci(value, alpha) {
|
|
return jStat.normalci(value, alpha, this.toArray());
|
|
},
|
|
|
|
tci: function tci(value, alpha) {
|
|
return jStat.tci(value, alpha, this.toArray());
|
|
}
|
|
});
|
|
|
|
// internal method for calculating the z-score for a difference of proportions test
|
|
function differenceOfProportions(p1, n1, p2, n2) {
|
|
if (p1 > 1 || p2 > 1 || p1 <= 0 || p2 <= 0) {
|
|
throw new Error("Proportions should be greater than 0 and less than 1")
|
|
}
|
|
var pooled = (p1 * n1 + p2 * n2) / (n1 + n2);
|
|
var se = Math.sqrt(pooled * (1 - pooled) * ((1/n1) + (1/n2)));
|
|
return (p1 - p2) / se;
|
|
}
|
|
|
|
// Difference of Proportions
|
|
jStat.extend(jStat.fn, {
|
|
oneSidedDifferenceOfProportions: function oneSidedDifferenceOfProportions(p1, n1, p2, n2) {
|
|
var z = differenceOfProportions(p1, n1, p2, n2);
|
|
return jStat.ztest(z, 1);
|
|
},
|
|
|
|
twoSidedDifferenceOfProportions: function twoSidedDifferenceOfProportions(p1, n1, p2, n2) {
|
|
var z = differenceOfProportions(p1, n1, p2, n2);
|
|
return jStat.ztest(z, 2);
|
|
}
|
|
});
|
|
|
|
}(jStat, Math));
|