UNPKG

21.6 kBJavaScriptView Raw
1var R=require("lodash");
2var J=require("jStat").jStat;
3
4R.M=require("numeric");
5
6var repeats=function(f, x, n) {
7 var a=[];
8 for (var i=0; i<n; i++) {
9 a.push(f(x));
10 }
11 return R(a);
12}
13
14R.mixin({repeats:repeats});
15
16var calls=function() {
17 var args = Array.prototype.slice.call(arguments);
18 var n = args[0];
19 var f = args[1];
20 var params = args.slice(2, args.length);
21 var a=[];
22 for (var i=0; i<n; i++)
23 a.push(f.apply(null, params));
24 return R(a);
25}
26
27R.mixin({calls:calls});
28
29var samples=function(space, size, arg) {
30 var arg = R.defaults(arg, {replace:true});
31 if (arg.replace)
32 return R.chain(R.sampleSize(space, size));
33 else
34 return R.repeats(R.sample, space, size);
35}
36
37R.mixin({samples:samples});
38
39R.steps=function(start, end, step) {
40 step = step || 1;
41 return R.range(start,end+0.00001*step, step);
42}
43
44// ============== format ==================
45R.precision = 2;
46// R.largeArray = 50;
47
48R.num2str=function(x) {
49 if (isNaN(x))
50 return "NaN";
51 else if (Math.floor(x) === x) // 整數
52 return x.toString();
53 else if (isFinite(x)) // 有小數點
54 return R.ctrim(x.toFixed(R.precision), "0", "right");
55 else if (x < 0)
56 return "-Infinity";
57 else
58 return "Infinity";
59}
60
61R.ctrim=function(s, set, side) {
62 side = side||"both";
63 for (var b=0; b<s.length; b++)
64 if (set.indexOf(s[b])<0) break;
65 for (var e=s.length-1; e>=0; e--)
66 if (set.indexOf(s[e])<0) break;
67 if (side === "right") b=0;
68 if (side === "left") e=s.length-1;
69 return s.substring(b, e+1);
70}
71
72R.array2str=function(x) {
73 var s = "";
74 for (var i in x)
75 s+= R.str(x[i])+", ";
76 return "["+R.ctrim(s, ", ")+"]";
77}
78
79R.obj2str=function(x, sp) {
80 var s = "";
81 for (var k in x)
82 s+= k+":"+R.str(x[k])+sp;
83 return "{"+R.ctrim(s,sp)+"}";
84}
85
86var str = function(x) {
87 if (typeof x === "number") return R.num2str(x);
88 else if(typeof x === "string") return '\"'+x.toString()+'\"';
89 else if (x instanceof Array) return R.array2str(x);
90 else if (typeof x === "object") return R.obj2str(x, ",");
91 else return x.toString();
92}
93
94R.mixin({str:str}, {chain:false});
95
96// ============== /format ==================
97
98var sd = function(a, flag) {
99 flag = flag || 1;
100 return J.stdev(a, flag);
101}
102
103R.mixin({sd:sd}, {chain:false});
104
105// 協方差
106R.cov = function(x, y) { return J.stdev(x, y); }
107// 相關係數
108R.cor = function(x, y) { return J.corrcoeff(x, y); }
109// 階層 n!
110R.factorial = function(n) { return J.factorial(n); }
111// log(n!)
112R.lfactorial = function(n) { return J.factorialln(n); }
113// 組合 C(n,m)
114R.choose = function(n,m) { return J.combination(n, m); }
115// log C(n,m)
116R.lchoose = function(n,m) { return J.combinationln(n, m); }
117// 組合 C(n,m)
118R.permutation = function(n,m) { return J.permutation(n, m); }
119// log C(n,m)
120R.lchoose = function(n,m) { return J.combinationln(n, m); }
121
122// 均等分布
123R.runif=function(n, a, b) { return R.calls(n, J.uniform.sample, a, b); }
124R.dunif=function(x, a, b) { return J.uniform.pdf(x, a, b); }
125R.punif=function(q, a, b) { return J.uniform.cdf(q, a, b); }
126R.qunif=function(p, a, b) { return J.uniform.inv(p, a, b); }
127// 常態分布
128R.rnorm=function(n, mean, sd) { return R.calls(n, J.normal.sample, mean, sd); }
129R.dnorm=function(x, mean, sd) { return J.normal.pdf(x, mean, sd); }
130R.pnorm=function(q, mean, sd) { return J.normal.cdf(q, mean, sd); }
131R.qnorm=function(p, mean, sd) { return J.normal.inv(p, mean, sd); }
132// 布瓦松分布
133R.rpois=function(n, l) { return R.calls(n, J.poisson.sample, l); }
134R.dpois=function(x, l) { return J.poisson.pdf(x, l); }
135R.ppois=function(q, l) { return J.poisson.cdf(q, l); }
136R.qpois=function(p, l) { return J.poisson.inv(p, l); }
137// F 分布
138R.rf=function(n, df1, df2) { return R.calls(n, J.centralF.sample, df1, df2); }
139R.df=function(x, df1, df2) { return J.centralF.pdf(x, df1, df2); }
140R.pf=function(q, df1, df2) { return J.centralF.cdf(q, df1, df2); }
141R.qf=function(p, df1, df2) { return J.centralF.inv(p, df1, df2); }
142// T 分布
143R.rt=function(n, dof) { return R.calls(n, J.studentt.sample, dof); }
144R.dt=function(x, dof) { return J.studentt.pdf(x, dof); }
145R.pt=function(q, dof) { return J.studentt.cdf(q, dof); }
146R.qt=function(p, dof) { return J.studentt.inv(p, dof); }
147// Beta 分布
148R.rbeta=function(n, alpha, beta) { return R.calls(n, J.beta.sample, alpha, beta); }
149R.dbeta=function(x, alpha, beta) { return J.beta.pdf(x, alpha, beta); }
150R.pbeta=function(q, alpha, beta) { return J.beta.cdf(q, alpha, beta); }
151R.qbeta=function(p, alpha, beta) { return J.beta.inv(p, alpha, beta); }
152// 柯西分布
153R.rcauchy=function(n, local, scale) { return R.calls(n, J.cauchy.sample, local, scale); }
154R.dcauchy=function(x, local, scale) { return J.cauchy.pdf(x, local, scale); }
155R.pcauchy=function(q, local, scale) { return J.cauchy.cdf(q, local, scale); }
156R.qcauchy=function(p, local, scale) { return J.cauchy.inv(p, local, scale); }
157// chisquare 分布
158R.rchisq=function(n, dof) { return R.calls(n, J.chisquare.sample, dof); }
159R.dchisq=function(x, dof) { return J.chisquare.pdf(x, dof); }
160R.pchisq=function(q, dof) { return J.chisquare.cdf(q, dof); }
161R.qchisq=function(p, dof) { return J.chisquare.inv(p, dof); }
162// 指數分布
163R.rexp=function(n, rate) { return R.calls(n, J.exponential.sample, rate); }
164R.dexp=function(x, rate) { return J.exponential.pdf(x, rate); }
165R.pexp=function(q, rate) { return J.exponential.cdf(q, rate); }
166R.qexp=function(p, rate) { return J.exponential.inv(p, rate); }
167// Gamma 分布
168R.rgamma=function(n, shape, scale) { return R.calls(n, J.gamma.sample, shape, scale); }
169R.dgamma=function(x, shape, scale) { return J.gamma.pdf(x, shape, scale); }
170R.pgamma=function(q, shape, scale) { return J.gamma.cdf(q, shape, scale); }
171R.qgamma=function(p, shape, scale) { return J.gamma.inv(p, shape, scale); }
172// 反 Gamma 分布
173R.rinvgamma=function(n, shape, scale) { return R.calls(n, J.invgamma.sample, shape, scale); }
174R.dinvgamma=function(x, shape, scale) { return J.invgamma.pdf(x, shape, scale); }
175R.pinvgamma=function(q, shape, scale) { return J.invgamma.cdf(q, shape, scale); }
176R.qinvgamma=function(p, shape, scale) { return J.invgamma.inv(p, shape, scale); }
177// 對數常態分布
178R.rlognormal=function(n, mu, sigma) { return R.calls(n, J.lognormal.sample, mu, sigma); }
179R.dlognormal=function(x, mu, sigma) { return J.lognormal.pdf(x, mu, sigma); }
180R.plognormal=function(q, mu, sigma) { return J.lognormal.cdf(q, mu, sigma); }
181R.qlognormal=function(p, mu, sigma) { return J.lognormal.inv(p, mu, sigma); }
182// Pareto 分布
183R.rpareto=function(n, scale, shape) { return R.calls(n, J.pareto.sample, scale, shape); }
184R.dpareto=function(x, scale, shape) { return J.pareto.pdf(x, scale, shape); }
185R.ppareto=function(q, scale, shape) { return J.pareto.cdf(q, scale, shape); }
186R.qpareto=function(p, scale, shape) { return J.pareto.inv(p, scale, shape); }
187// Weibull 分布
188R.rweibull=function(n, scale, shape) { return R.calls(n, J.weibull.sample, scale, shape); }
189R.dweibull=function(x, scale, shape) { return J.weibull.pdf(x, scale, shape); }
190R.pweibull=function(q, scale, shape) { return J.weibull.cdf(q, scale, shape); }
191R.qweibull=function(p, scale, shape) { return J.weibull.inv(p, scale, shape); }
192// 三角分布
193R.rtriangular=function(n, a, b, c) { return R.calls(n, J.triangular.sample, a, b, c); }
194R.dtriangular=function(x, a, b, c) { return J.triangular.pdf(x, a, b, c); }
195R.ptriangular=function(q, a, b, c) { return J.triangular.cdf(q, a, b, c); }
196R.qtriangular=function(p, a, b, c) { return J.triangular.inv(p, a, b, c); }
197// 類似 Beta 分布,但計算更簡單
198R.rkumaraswamy=function(n, alpha, beta) { return R.calls(n, J.kumaraswamy.sample, alpha, beta); }
199R.dkumaraswamy=function(x, alpha, beta) { return J.kumaraswamy.pdf(x, alpha, beta); }
200R.pkumaraswamy=function(q, alpha, beta) { return J.kumaraswamy.cdf(q, alpha, beta); }
201R.qkumaraswamy=function(p, alpha, beta) { return J.kumaraswamy.inv(p, alpha, beta); }
202
203// ============= 離散分佈 ============
204var qf=function(cdf, q, N, p) {
205 for (var i=0; i<=N; i++) {
206 if (cdf(i, N, p) > q) return i;
207 }
208 return N;
209}
210var rf=function(cdf, n, N, p) {
211 var samples = [];
212 for (var i=0; i<n; i++) {
213 var q = Math.random();
214 samples.push(cdf(q, N, p));
215 }
216 return samples;
217}
218// 二項分布
219R.dbinom=function(x, N, p) { return J.binomial.pdf(x, N, p); }
220R.pbinom=function(k, N, p) { return J.binomial.cdf(k, N, p); }
221R.qbinom=function(q, N, p) { return qf(R.pbinom, q, N, p); }
222R.rbinom=function(n, N, p) { return rf(R.qbinom, n, N, p); }
223// 負二項分布
224R.dnbinom=function(x, N, p) { return jStat.negbin.pdf(x, N, p); }
225R.pnbinom=function(k, N, p) { return jStat.negbin.cdf(k, N, p); }
226R.qnbinom=function(q, N, p) { return qf(R.pnbinom, q, N, p); }
227R.rnbinom=function(n, N, p) { return rf(R.qnbinom, n, N, p); }
228// 超幾何分布
229R.dhyper=function(x, N, m, n) { return jStat.hypgeom.pdf(x, N, m, n); }
230R.phyper=function(k, N, m, n) { return jStat.hypgeom.cdf(k, N, m, n); }
231R.qhyper=function(q, N, m, n) { return qf(R.phyper, q, N, p); }
232R.rhyper=function(n, N, m, k) { return rf(R.qhyper, n, N, p); }
233
234// =============== 檢定 ==============================
235
236// ---------------- 統計與檢定 ----------------------
237function opAlt(op) {
238 if (op === "=") return "!=";
239 if (op === "<") return ">=";
240 if (op === ">") return "<=";
241 return null;
242}
243
244R.test = function(o) { // name, D, x, mu, sd, y, alpha, op
245 o = R.defaults(o, {alpha:0.05, op:"="});
246 var alpha = o.alpha;
247 var pvalue, interval;
248 var D = o.D;
249 var q1 = D.o2q(o); // 單尾檢定的 pvalue
250
251 if (o.op === "=") {
252 if (q1>0.5) q1 = 1-q1; // (q1>0.5) 取右尾,否則取左尾。
253 pvalue= 2*q1; // 對稱情況:雙尾檢定的 p 值是單尾的兩倍。
254 interval = [D.q2p(alpha/2, o, "L"), D.q2p(1-alpha/2, o, "R")];
255 } else {
256 if (o.op === "<") { // 右尾檢定 H0: q < 1-alpha,
257 interval = [ D.q2p(alpha, o, "L"), Infinity ];
258 pvalue = 1-q1;
259 }
260 if (o.op === ">") { // 左尾檢定 H0: q > alpha
261 interval=[-Infinity, D.q2p(1-alpha, o, "R")];
262 pvalue = q1;
263 }
264 }
265 return {
266 name: o.name,
267 h: D.h(o),
268 alpha: alpha,
269 op: o.op,
270 pvalue: pvalue,
271 ci : interval,
272 df : D.df(o),
273 report: function() { R.report(this) }
274 };
275}
276
277var t1 = { // 單樣本 T 檢定 t = (X-mu)/(S/sqrt(n))
278 h:function(o) { return "H0:mu"+o.op+o.mu; },
279 o2q:function(o) {
280 var x = o.x, n = x.length;
281 var t = (R.mean(x)-o.mu)/(R.sd(x)/Math.sqrt(n));
282 return R.pt(t, n-1);
283 },
284 // P(X-mu/(S/sqrt(n))<t) = q ; 信賴區間 P(T<q)
285 // P(mu > X-t*S/sqrt(n)) = q ; 這反而成了右尾檢定,所以左尾與右尾確實會反過來
286 q2p:function(q, o) {
287 var x = o.x, n = x.length;
288 return R.mean(x) + R.qt(q, n-1) * R.sd(x) / Math.sqrt(n);
289 },
290 df:function(o) { return o.x.length-1; }
291}
292
293var t2vareq = { // σ1=σ2, 合併 T 檢定 (雙樣本)
294 h:function(o) { return "H0:mu1"+o.op+"mu2" },
295 // S^2 = (n1-1)*S1^2+(n2-1)*S2^2)/(n1-1+n2-1)
296 sd:function(o) {
297 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
298 var S1= R.sd(x), S2 = R.sd(y);
299 var S = Math.sqrt(((n1-1)*S1*S1+(n2-1)*S2*S2)/(n1-1+n2-1));
300 return S;
301 },
302 // T = ((X-Y)-(mu1-mu2))/(sqrt(1/n1+1/n2)*S)
303 o2q:function(o) {
304 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
305 var S = this.sd(o);
306 var t = (R.mean(x)-R.mean(y)-o.mu)/(Math.sqrt(1/n1+1/n2)*S);
307 return R.pt(t, n1+n2-2);
308 },
309 // t=((X-Y)-mu)/(sqrt(1/n1+1/n2)*S), (X-Y)-t*sqrt(1/n1+1/n2)*S = mu
310 q2p:function(q, o) {
311 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
312 var S = this.sd(o);
313 return R.mean(x)-R.mean(y)+ R.qt(q, n1+n2-2)*Math.sqrt(1/n1+1/n2)*S;
314 },
315 df:function(o) {
316 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
317 return n1+n2-2;
318 }
319}
320
321var t2paired = { // 成對 T 檢定 T = (X-Y-mu)/(S/sqrt(n)) (雙樣本)
322 h:function(o) { return "H0:mu1"+o.op+"mu2" },
323 sd:function(o) { // S = sd(x-y)
324 var x = o.x, n = x.length, y=o.y;
325 var S= R.sd(R.sub(x,y));
326 return S;
327 },
328 o2q:function(o) {
329 var x = o.x, n = x.length, y=o.y;
330 var S = this.sd(o);
331 var t = (R.mean(R.sub(x,y))-o.mu)/(S/Math.sqrt(n));
332 return R.pt(t, n-1);
333 },
334 // mean(x-y)+t*S/sqrt(n)
335 q2p:function(q, o) {
336 var x = o.x, n = x.length, y=o.y;
337 var S = this.sd(o);
338 return R.mean(R.sub(x,y))+ R.qt(q, n-1)*S/Math.sqrt(n);
339 },
340 df:function(o) {
341 return o.x.length-1;
342 }
343}
344
345var t2varneq = { // σ1≠σ2, Welch's t test (雙樣本) (又稱 Smith-Satterwaite 程序)
346// 參考:http://en.wikipedia.org/wiki/Welch's_t_test
347 h:function(o) { return "H0:mu1"+o.op+"mu2" },
348 // T = ((X-Y)-(mu1-mu2))/sqrt(S1^2/n1+S2^2/n2)
349 o2q:function(o) {
350 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
351 var S1 = R.sd(x), S2=R.sd(y);
352 var t = (R.mean(x)-R.mean(y)-o.mu)/Math.sqrt(S1*S1/n1+S2*S2/n2);
353 return R.pt(t, this.df(o));
354 },
355 // t=((X-Y)-mu)/sqrt(S1^2/n1+S2^2/n2), (X-Y)-t*sqrt(S1^2/n1+S2^2/n2) = mu
356 q2p:function(q, o) {
357 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
358 var S1 = R.sd(x), S2=R.sd(y);
359 return R.mean(x)-R.mean(y)+ R.qt(q, this.df(o))*Math.sqrt(S1*S1/n1+S2*S2/n2);
360 },
361 df:function(o) {
362 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
363 var S1 = R.sd(x), S2=R.sd(y);
364 var Sn1 = S1*S1/n1, Sn2 = S2*S2/n2, Sn12 = Sn1+Sn2;
365 var df = (Sn12*Sn12)/((Sn1*Sn1)/(n1-1)+(Sn2*Sn2)/(n2-1));
366 return df;
367 }
368}
369
370R.ttest = function(o) {
371 var t;
372 if (typeof o.y === "undefined") {
373 o.name = "ttest(X)";
374 o.D = t1;
375 t = R.test(o);
376 t.mean = R.mean(o.x);
377 t.sd = R.sd(o.x);
378 } else {
379 var varequal = R.opt(o, "varequal", false);
380 var paired = R.opt(o, "paired", false);
381 if (varequal) {
382 o.name = "ttest(X,Y,mu="+o.mu+",varequal=true) (pooled)";
383 o.D = t2vareq;
384 t = R.test(o);
385 } else if (paired) {
386 o.name = "ttest(x,y,mu="+o.mu+",paired=true)";
387 o.D = t2paired;
388 t = R.test(o);
389 t.mean = "mean(x-y)="+R.str(R.mean(R.sub(o.x, o.y)));
390 t.sd = "sd(x-y)="+R.str(R.sd(R.sub(o.x, o.y)));
391 } else {
392 o.name = "ttest(x,y,mu="+o.mu+",varequal=false), Welch t-test";
393 o.D = t2varneq;
394 t = R.test(o);
395 }
396 if (typeof t.mean === "undefined") {
397 t.mean = "mean(x)="+R.str(R.mean(o.x))+" mean(y)="+R.str(R.mean(o.y));
398 t.sd = "sd(x)="+R.str(R.sd(o.x))+" sd(y)="+R.str(R.sd(o.y));
399 }
400 }
401 return t;
402}
403
404var f2 = { // 檢定 σ1/σ2 = 1?
405 h:function(o) { return "H0:σ1/σ2"+o.op+"1"; },
406 // F = S1^2/S2^2
407 o2q:function(o) {
408 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
409 var S1 = R.sd(x), S2=R.sd(y);
410 var f = (S1*S1)/(S2*S2);
411 var pf = R.pf(f, n1-1, n2-1);
412 return pf;
413 },
414 // 信賴區間公式: S1^2/(S2^2*F(1-α/2), S1^2/(S2^2*F(α/2))
415 // 也就是要用 S1^2/(S2^2*f(1-q)) ,參考 R 軟體、應用統計方法 (陳景祥) 389 頁。
416 q2p:function(q, o) {
417 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
418 var S1 = R.sd(x), S2=R.sd(y);
419 var qf = R.qf(1-q, n1-1, n2-1);
420 return (S1*S1)/(S2*S2*qf);
421 },
422 df:function(o) {
423 var x = o.x, n1 = x.length, y=o.y, n2=y.length;
424 return [n1-1, n2-1];
425 }
426}
427
428R.ftest = function(o) {
429 o.name = "ftest(X, Y)";
430 o.D = f2;
431 var t = R.test(o);
432 var rsd = R.sd(o.x)/R.sd(o.y);
433 t.ratio = (rsd*rsd);
434 return t;
435}
436
437// R 軟體沒有此函數,測試請看湯銀才 143 頁
438var chisq1 = { // 檢定 σ1 = σ ?
439 h:function(o) { return "H0:σ1"+o.op+"σ"; },
440 // χ(n-1) = (n-1)S^2/σ^2
441 o2q:function(o) {
442 var x = o.x, n = x.length, S=R.sd(x);
443 var v = (n-1)*S*S/(o.sd*o.sd);
444 return R.pchisq(v, n-1);
445 },
446 // 信賴區間公式: (n-1)S^2/χ^2(1-q),參考 R 語言與統計分析 (湯銀才) 142 頁。
447 q2p:function(q, o) {
448 var x = o.x, n = x.length, S=R.sd(x);
449 return (n-1)*S*S/R.qchisq(1-q, n-1);
450 },
451 df:function(o) {
452 var x = o.x, n = x.length;
453 return n-1;
454 }
455}
456
457R.chisqtest = function(o) {
458 o.name = "chisqtest(X)";
459 o.D = chisq1;
460 return R.test(o);
461}
462
463R.vartest = function(o) {
464 if (typeof o.y === "undefined")
465 return R.chisqtest(o);
466 else
467 return R.ftest(o);
468}
469
470var z1 = { // 單樣本 Z 檢定
471 h:function(o) { return "H0:mu"+o.op+o.mu+" when sd="+o.sd; },
472 o2q:function(o) {
473 var x = o.x, n = x.length;
474 var z = (R.mean(x)-o.mu)/(o.sd/Math.sqrt(n)); // z=(X-mu)/(sd/sqrt(n))
475 return R.pnorm(z, 0, 1);
476 },
477 q2p:function(q, o) {
478 var x = o.x, n = x.length;
479 return R.mean(x) + R.qnorm(q, 0, 1) * R.sd(x) / Math.sqrt(n);
480 },
481 df:function(o) { return o.x.length; }
482}
483
484R.ztest = function(o) {
485 o.name = "ztest(X)";
486 o.D = z1;
487 return R.test(o);
488}
489
490var zprop1 = { // 比例的檢定, n 較大時的近似解 o={ x, n, p } // x 為數值,n 個中出現 x 個 1
491 h:function(o) { return "H0:p"+o.op+o.p; },
492 // Z = (p1-p)/sqrt(p(1-p)/n)
493 o2q:function(o) {
494 var x=o.x, n=o.n, p1=x/n, p=R.def(o.p, p1);
495 var z = (p1-p)/Math.sqrt(p*(1-p)/n);
496 return R.pnorm(z, 0, 1);
497 },
498 // 信賴區間公式: p1+z*sqrt(p1*(1-p1)/n),參考 R 語言與統計分析 (湯銀才) 149 頁。
499 q2p:function(q, o) {
500 var x=o.x, n=o.n, p1=x/n, p=p1;
501 var z = R.qnorm(q, 0, 1);
502 var z22n = z*z/(2*n);
503 return (p1+z22n+z*Math.sqrt( p*(1-p)/n + z22n/(2*n) ))/(1+2*z22n); // R 的版本,比較複雜的估計公式
504// return p1+z*Math.sqrt(p*(1-p)/n); // 語言與統計分析 (湯銀才) 149 頁的版本。
505 },
506 df:function(o) { return 1; }
507}
508
509var zprop2 = { // 比例的檢定, n 較大時的近似解 o={ x, y, n1, n2 }
510 h:function(o) { return "H0:p1-p2"+o.op+o.p; },
511 // Z = (p1-p2)/sqrt(p*(1-p)*(1/n1+1/n2)), p = (n1p1+n2p2)/(n1+n2),參考 R 語言與統計分析 (湯銀才) 175 頁。
512 o2q:function(o) {
513 var x=o.x, y=o.y, n1=o.n1, n2=o.n2, p1=x/n1, p2=y/n2, p=(n1*p1+n2*p2)/(n1+n2);
514 var z = (p1-p2)/Math.sqrt(p*(1-p)*(1/n1+1/n2));
515 return R.pnorm(z, 0, 1);
516 },
517 // 信賴區間公式: p1-p2+z*sqrt(p*(1-p)*(1/n1+1/n2));
518 q2p:function(q, o) {
519 var x=o.x, y=o.y, n1=o.n1, n2=o.n2, p1=x/n1, p2=y/n2, p=(n1*p1+n2*p2)/(n1+n2);
520 var z = R.qnorm(q, 0, 1);
521 return p1-p2+z*Math.sqrt(p*(1-p)*(1/n1+1/n2));
522 },
523 df:function(o) { return 1; }
524}
525
526/* 在 prop.test.R 當中,雙邊檢定的 pvalue 是用 pchisq, 單邊才是用 z ,為何呢? ( 但是信賴區間則是全部用 z)
527 if (alternative == "two.sided")
528 PVAL <- pchisq(STATISTIC, PARAMETER, lower.tail = FALSE)
529 else {
530 if (k == 1)
531 z <- sign(ESTIMATE - p) * sqrt(STATISTIC)
532 else
533 z <- sign(DELTA) * sqrt(STATISTIC)
534 PVAL <- pnorm(z, lower.tail = (alternative == "less"))
535 }
536*/
537
538R.proptest = function(o) {
539 o.p = R.opt(o, "p", 0.5);
540 o.name = "proptest("+R.str(o)+")";
541 o.correct = R.opt(o.correct, false);
542 if (o.correct) {
543 o.name += ", binomtest";
544 o.D += binom1;
545 } else {
546 if (typeof o.y === "undefined") {
547 o.name += ", zprop1";
548 o.D = zprop1;
549 } else {
550 o.p = 0; // p1-p2 = 0
551 o.name += ", zprop2";
552 o.D = zprop2;
553 }
554 }
555 var t=R.test(o);
556 if (typeof o.y === "undefined")
557 t.p = o.x/o.n;
558 else
559 t.p = [o.x/o.n1, o.y/o.n2];
560 return t;
561}
562
563// 參考: https://github.com/SurajGupta/r-source/blob/master/src/library/stats/R/binom.test.R
564var binom1 = { // 比例的檢定, n 較大時的近似解 o={ x, n, p } // x 為數值,n 個中出現 x 個 1
565 h:function(o) { return "H0:p"+o.op+o.p; },
566
567 // Z = C(n, k)*p1^k*(1-p1)^(n-k), CDF(z: from 1 to x)
568 o2q:function(o) {
569 var x=o.x, n=o.n, p = o.p, q;
570 var dx = R.dbinom(x, n, p);
571 if (o.op === "=") { // 雙尾檢定,去雙尾後 / 2
572 var q = 0;
573 for (var i=0; i<=n; i++) {
574 var di = R.dbinom(i, n, p);
575 if (di > dx+1e-5) q += di; // 為何 x 本身不算,如果算應該用 di > dx-1e-5 才對。
576 }
577 q=1-((1-q)/2); // 因為 test 會 * 2 所進行的減半調整
578 } else { // 單尾檢定
579 if (Math.abs(x - n*p)<1e-5) // 正確預測, q=1
580 q = 1;
581 else {
582 if (o.op === ">")
583 q = R.pbinom(x, n, p); // 去右尾
584 else // op=== "<"
585 q = R.pbinom(x-1, n, p); // 去右尾
586 }
587 }
588 return q;
589 },
590/* 注意上述 R 原始碼另一尾的計算方式,是用 < pbinom(最接近 x 者) 的算法,而不是直接 * 2。 問題是我們在 test 中是直接用*2 的方式。
591 d <- dbinom(x, n, p)
592 ...
593 else if (x < m) {
594 i <- seq.int(from = ceiling(m), to = n)
595 y <- sum(dbinom(i, n, p) <= d * relErr)
596 pbinom(x, n, p) 左尾 + pbinom(n - y, n, p, lower.tail = FALSE) 右尾
597 } else {
598 i <- seq.int(from = 0, to = floor(m))
599 y <- sum(dbinom(i, n, p) <= d * relErr)
600 pbinom(y - 1, n, p) 左尾 + pbinom(x - 1, n, p, lower.tail = FALSE) 右尾
601 }
602*/
603 // 信賴區間公式: P(T>c) = Σ (n, i) C(n, i) p1^i (1-p1)^(n-i) for i>c < q
604
605 q2p:function(q, o, side) {
606 var x=o.x, n=o.n, p=o.p, op=o.op;
607 if (side === "L")
608 return qbeta(q, x, n - x + 1); // 這裏採用 qbeta 是 R 的作法; 直覺上應該採用 R.qbinom(q, n, p);
609 else
610 return qbeta(q, x + 1, n - x);
611 },
612 df:function(o) { return 1; }
613}
614
615R.binomtest = function(o) {
616 o.p = R.opt(o, "p", 0.5);
617 o.name = "binomtest("+R.str(o)+")";
618 o.D = binom1;
619 var t=R.test(o);
620 t.p = o.x/o.n;
621 t.ci[0]=(o.op === ">")?0:t.ci[0];
622 t.ci[1]=(o.op === "<")?1:t.ci[1];
623 return t;
624}
625
626R.report = function(o) {
627 console.log("=========== report ==========");
628 for (var k in o) {
629 if (typeof o[k] !== "function")
630 console.log(k+"\t: "+str(o[k]));
631 }
632}
633
634// anova f-test : array1, array2, array3, ...
635R.anovaftest = function() {
636 return {
637 h0 : "σ1=σ2=...=σ"+arguments.length,
638 pvalue: J.anovaftest(),
639 score: J.anovafscore(),
640 };
641}
642
643module.exports = R;