UNPKG

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