UNPKG

als-statistics

Version:

Modular JS statistics toolkit for Node.js and the browser: descriptive stats, correlations (Pearson/Spearman/Kendall), t-tests & ANOVA (Student/Welch), reliability (Cronbach’s alpha), regression (linear/logistic), clustering (DBSCAN/HDBSCAN), and table/co

61 lines (50 loc) 2.38 kB
import CDF from '../cdf/index.js'; import { TestBase } from '../test-base/index.js' export class IndependentTTest extends TestBase { /** Independent-samples t-test (Student/Welch) + Levene’s test (как в SPSS) */ constructor(samples, welch = false) { super(samples, 'Independent T Test', [ 't','df','p','F', 'leveneF','leveneDf1','leveneDf2','leveneP', 'k']); this.#calcT(welch); this.#calcLevene(); } #calcT(welch) { const { mean: m1, n: n1, varianceSample: v1 } = this.samples[0]; const { mean: m2, n: n2, varianceSample: v2 } = this.samples[1]; if (welch) { const se2 = v1 / n1 + v2 / n2; const den = ((v1 / n1) ** 2) / (n1 - 1) + ((v2 / n2) ** 2) / (n2 - 1); // Саттертуэйт this.t = (m1 - m2) / Math.sqrt(se2); this.df = (se2 * se2) / den; } else { this.df = n1 + n2 - 2; const sp2 = ((n1 - 1) * v1 + (n2 - 1) * v2) / this.df; // pooled variance this.t = (m1 - m2) / Math.sqrt(sp2 * (1 / n1 + 1 / n2)); } } #calcLevene() { /** Levene’s test (на основе средних абсолютных отклонений; как в отчёте SPSS) */ const k = this.k; const N = this.samples.reduce((s, g) => s + g.n, 0); // Для каждой группы считаем |x_ij - mean_i| const zGroups = this.samples.map(({ values, mean }) => values.map(v => Math.abs(v - mean)) ); const n = zGroups.map(z => z.length); const zbar_i = zGroups.map((z, i) => z.reduce((a, b) => a + b, 0) / n[i]); const zbar = zbar_i.reduce((s, zi, i) => s + n[i] * zi, 0) / N; // ANOVA для z: SSB и SSW const ssb = zbar_i.reduce((s, zi, i) => s + n[i] * (zi - zbar) ** 2, 0); const ssw = zGroups.reduce((s, z, i) => s + z.reduce((acc, zij) => acc + (zij - zbar_i[i]) ** 2, 0), 0 ); const df1 = k - 1; const df2 = N - k; const msb = ssb / df1; const msw = ssw / df2; const F = msb / msw; this.leveneF = F; this.leveneDf1 = df1; this.leveneDf2 = df2; this.leveneP = 1 - CDF.f(F, df1, df2); // правохвостовая p } get p() { return 2 * (1 - CDF.t(Math.abs(this.t), this.df)); } /** Двухсторонний p-value для t */ get F() { return this.t * this.t; } /** F для различий средних (ANOVA-эквивалент): F = t^2 */ }