C 语言实现独立样本 t 检验和配对样本 t 检验

源代码链接:https://github.com/Illusionna/tiny-stats/blob/main/t-test.c

cpp 复制代码
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>


// Box-Muller Transform.
double random_normal(double mu, double sigma) {
    static double U;
    static double V;
    static int phase = 0;
    double Z;

    if (phase == 0) {
        U = (rand() + 1.0) / (RAND_MAX + 1.0);
        V = (rand() + 1.0) / (RAND_MAX + 1.0);
        Z = sqrt(-2.0 * log(U)) * sin(2.0 * M_PI * V);
    } else {
        Z = sqrt(-2.0 * log(U)) * cos(2.0 * M_PI * V);
    }
    phase = 1 - phase;

    return Z * sigma + mu;
}


double incbeta(double a, double b, double x) {
    static const double epsilon = 1.0e-30;
    static const double condition = 1.0e-8;

    if (x < 0.0 || x > 1.0) return INFINITY;
    if (x > (a + 1.0) / (a + b + 2.0)) return 1.0 - incbeta(b, a, 1.0 - x);

    double f = 1.0;
    double c = 1.0;
    double d = 0.0;
    const double lbeta_ab = lgamma(a) + lgamma(b) - lgamma(a + b);
    const double front = exp(a * log(x) + b * log(1.0 - x) - lbeta_ab) / a;

    for (int i = 0; i <= 200; ++i) {
        int m = i / 2;
        double numerator;

        if (i == 0) numerator = 1.0;
        else if (i % 2 == 0) numerator = (m * (b - m) * x) / ((a + 2.0 * m - 1.0) * (a + 2.0 * m));
        else numerator = - ((a + m) * (a + b + m) * x) / ((a + 2.0 * m) * (a + 2.0 * m + 1));

        d = 1.0 + numerator * d;
        if (fabs(d) < epsilon) d = epsilon;
        d = 1.0 / d;

        c = 1.0 + numerator / c;
        if (fabs(c) < epsilon) c = epsilon;

        double cd = c * d;
        f = f * cd;
        if (fabs(1.0 - cd) < condition) return front * (f - 1.0);
    }
    return INFINITY;
}


double cdf_student_t(double t, double df) {
    /*
    double x = df / (t * t + df);
    double p = 0.5 * incbeta(df / 2.0, 0.5, x);
    return (t > 0) ? (1.0 - p) : p;
    */
    if (df <= 0.0) return NAN;
    if (t == 0.0) return 0.5;
    double cache = sqrt(t * t + df);
    return incbeta(df / 2.0, df / 2.0, (t + cache) / (2.0 * cache));
}


double ttest_independent(double *group1, double *group2, int n1, int n2, int equal_var) {
    double sum1 = 0.0;
    double sum2 = 0.0;
    for (int i = 0; i < n1; ++i) sum1 = sum1 + group1[i];
    for (int i = 0; i < n2; ++i) sum2 = sum2 + group2[i];
    double mean1 = sum1 / n1;
    double mean2 = sum2 / n2;

    double var1 = 0.0;
    double var2 = 0.0;
    for (int i = 0; i < n1; ++i) var1 = var1 + (group1[i] - mean1) * (group1[i] - mean1);
    for (int i = 0; i < n2; ++i) var2 = var2 + (group2[i] - mean2) * (group2[i] - mean2);
    var1 = var1 / (n1 - 1);
    var2 = var2 / (n2 - 1);

    double t;
    double df;

    if (equal_var) {
        df = n1 + n2 - 2.0;
        double pooled_var = ((n1 - 1.0) * var1 + (n2 - 1.0) * var2) / df;
        t = (mean1 - mean2) / sqrt(pooled_var * (1.0 / n1 + 1.0 / n2));
    } else {
        double satterthwaite1 = var1 / n1;
        double satterthwaite2 = var2 / n2;
        t = (mean1 - mean2) / sqrt(satterthwaite1 + satterthwaite2);
        double numerator = (satterthwaite1 + satterthwaite2) * (satterthwaite1 + satterthwaite2);
        double denominator = (satterthwaite1 * satterthwaite1) / (n1 - 1.0) + (satterthwaite2 * satterthwaite2) / (n2 - 1.0);
        df = numerator / denominator;
    }

    double cdf = cdf_student_t(t, df);
    return 2.0 * (cdf > 0.5 ? 1.0 - cdf : cdf);
}


double ttest_paired(double *state1, double *state2, int n) {
    if (n < 2) return NAN;

    double sum_diff = 0.0;
    double sum_square_diff = 0.0;
    for (int i = 0; i < n; ++i) {
        double diff = state1[i] - state2[i];
        sum_diff = sum_diff + diff;
        sum_square_diff = sum_square_diff + diff * diff;
    }

    double mean_diff = sum_diff / n;
    double var_diff = (sum_square_diff - (sum_diff * sum_diff / n)) / (n - 1);
    double std_error = sqrt(var_diff / n);

    double t = mean_diff / std_error;
    double cdf = cdf_student_t(t, n - 1.0);
    double p = 2.0 * (cdf > 0.5 ? 1.0 - cdf : cdf);
    return p;
}



int main(int argc, char *argv[], char *envs[]) {
    double p;
    srand((unsigned int)time(NULL));

    int n1 = 6;
    int n2 = 4;
    double mu1 = 75.0;
    double mu2 = 82.0;
    double sigma1 = 8.0;
    double sigma2 = 8.0;

    double category1[n1];
    double category2[n2];

    for (int i = 0; i < n1; ++i) category1[i] = random_normal(mu1, sigma1);
    for (int i = 0; i < n2; ++i) category2[i] = random_normal(mu2, sigma2);
    p = ttest_independent(category1, category2, n1, n2, sigma1 == sigma2);
    printf("Independent Samples T-test:\x1b[32m p = %.12lf\x1b[0m\n", p);

    double before[] = {22, 20, 19, 24, 25, 25, 28, 22, 30, 27, 24, 18, 16, 19, 19, 28, 24, 25, 25, 23};
    double after[] = {24, 22, 19, 22, 28, 26, 28, 24, 30, 29, 25, 20, 17, 18, 18, 28, 26, 27, 27, 24};
    p = ttest_paired(before, after, sizeof(after) / sizeof(after[0]));
    printf("Paired Sample T-test:\x1b[32m p = %.12lf\x1b[0m\n", p);

    return 0;
}
相关推荐
龚礼鹏21 小时前
Android应用程序 c/c++ 崩溃排查流程二——AddressSanitizer工具使用
android·c语言·c++
Herbert_hwt1 天前
C语言结构体操作符详解:从入门到精通的全方位指南
c语言
代码游侠1 天前
应用——MQTT客户端开发
服务器·c语言·开发语言·数据结构·算法
暴风鱼划水1 天前
三维重建【4-C】3D Gaussian Splatting:代码调试方法
c语言·开发语言
CS创新实验室1 天前
正态分布的深入学习:从数学发现到自然法则的演变
学习·数据挖掘·数据分析·统计学·正态分布
Tiger Z1 天前
《R for Data Science (2e)》免费中文翻译 (第17章) --- Dates and times(1)
r语言·编程·数据科学
福楠1 天前
模拟实现stack、queue、priority_queue
c语言·开发语言·数据结构·c++
济6171 天前
linux(第十二期)--裸机实验(C 语言版 LED 灯实验)-- Ubuntu20.04
linux·c语言
MindCareers1 天前
Beta Sprint Day 1-2: Alpha Issue Fixes Initiated + Mobile Project Setup
android·c语言·数据库·c++·qt·sprint·issue