用 C 语言计算决定系数(R²)

CBeginner
立即练习

简介

在本实验中,我们将学习如何用 C 语言计算决定系数(R²)。本实验涵盖以下步骤:

首先,我们将使用线性回归计算预测的 y 值。我们将创建一个程序,根据简单线性回归模型计算预测值。然后,我们将使用解释变差和总变差计算 R²值。最后,我们将输出 R²值。

本实验提供了一种实用的方法,来理解决定系数的概念及其在 C 编程中的实现,这对于统计数据分析来说是一项宝贵的技能。

使用回归计算预测的 y

在这一步中,我们将学习如何在 C 语言中使用线性回归计算预测的 y 值。我们将创建一个程序,根据简单线性回归模型计算预测值。

首先,为我们的回归计算创建一个 C 文件:

cd ~/project
nano regression_prediction.c

现在,输入以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// 计算预测 y 值的函数
void computePredictedY(double *x, double *y, int n, double slope, double intercept, double *predicted_y) {
    for (int i = 0; i < n; i++) {
        predicted_y[i] = slope * x[i] + intercept;
    }
}

int main() {
    // 示例数据点
    double x[] = {1.0, 2.0, 3.0, 4.0, 5.0};
    double y[] = {2.0, 4.0, 5.0, 4.0, 5.0};
    int n = sizeof(x) / sizeof(x[0]);

    // 预定义的斜率和截距(用于演示)
    double slope = 0.6;
    double intercept = 1.5;

    // 用于存储预测 y 值的数组
    double predicted_y[n];

    // 计算预测 y 值
    computePredictedY(x, y, n, slope, intercept, predicted_y);

    // 输出原始 y 值和预测 y 值
    printf("原始 y 值与预测 y 值对比:\n");
    for (int i = 0; i < n; i++) {
        printf("X: %.1f, 原始 y 值:%.1f, 预测 y 值:%.1f\n",
               x[i], y[i], predicted_y[i]);
    }

    return 0;
}

编译程序:

gcc -o regression_prediction regression_prediction.c -lm

运行程序:

./regression_prediction

示例输出:

原始y值与预测y值对比:
X: 1.0, 原始y值: 2.0, 预测y值: 2.1
X: 2.0, 原始y值: 4.0, 预测y值: 2.7
X: 3.0, 原始y值: 5.0, 预测y值: 3.3
X: 4.0, 原始y值: 4.0, 预测y值: 3.9
X: 5.0, 原始y值: 5.0, 预测y值: 4.5

让我们来剖析一下这段代码的关键部分:

  1. computePredictedY() 函数使用线性回归方程 y = mx + b 计算预测的 y 值
  2. 我们使用预定义的斜率(0.6)和截距(1.5)用于演示
  3. 程序输出原始 y 值和预测 y 值以便对比

使用解释变差/总变差计算 R²

在这一步中,我们将扩展之前的回归程序来计算决定系数(R²),它衡量回归模型对数据的拟合程度。

首先,修改我们现有的 C 文件:

cd ~/project
nano r_squared_calculation.c

输入以下完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// 计算数组均值的函数
double calculateMean(double *arr, int n) {
    double sum = 0.0;
    for (int i = 0; i < n; i++) {
        sum += arr[i];
    }
    return sum / n;
}

// 计算 R 平方的函数
double computeRSquared(double *x, double *y, int n, double slope, double intercept) {
    // 计算预测的 y 值
    double predicted_y[n];
    double total_variation = 0.0;
    double explained_variation = 0.0;

    // 计算实际 y 值的均值
    double y_mean = calculateMean(y, n);

    // 计算变差
    for (int i = 0; i < n; i++) {
        // 预测的 y 值
        predicted_y[i] = slope * x[i] + intercept;

        // 总变差(与均值的距离)
        total_variation += pow(y[i] - y_mean, 2);

        // 解释变差(与预测值的距离)
        explained_variation += pow(y[i] - predicted_y[i], 2);
    }

    // 计算 R 平方
    return 1 - (explained_variation / total_variation);
}

int main() {
    // 示例数据点
    double x[] = {1.0, 2.0, 3.0, 4.0, 5.0};
    double y[] = {2.0, 4.0, 5.0, 4.0, 5.0};
    int n = sizeof(x) / sizeof(x[0]);

    // 预定义的斜率和截距(用于演示)
    double slope = 0.6;
    double intercept = 1.5;

    // 计算并输出 R 平方
    double r_squared = computeRSquared(x, y, n, slope, intercept);

    printf("回归分析结果:\n");
    printf("斜率:%.2f\n", slope);
    printf("截距:%.2f\n", intercept);
    printf("R 平方 (R²): %.4f\n", r_squared);

    return 0;
}

编译程序:

gcc -o r_squared_calculation r_squared_calculation.c -lm

运行程序:

./r_squared_calculation

示例输出:

回归分析结果:
斜率: 0.60
截距: 1.50
R平方 (R²): 0.5600

R² 计算的关键部分:

  1. calculateMean() 计算数组的平均值
  2. computeRSquared() 使用公式 1 - (解释变差 / 总变差) 计算 R²
  3. 总变差衡量实际 y 值围绕其均值的离散程度
  4. 解释变差衡量预测值与实际值之间的离散程度
  5. R² 的范围是 0 到 1,值越高表示模型拟合越好

输出 R² 值

在这最后一步中,我们将创建一个完整的程序,该程序从文件读取数据、计算回归参数,并输出带有详细解释的 R² 值。

首先,创建一个示例数据文件:

cd ~/project
nano regression_data.txt

添加示例回归数据:

1.0 2.0
2.0 4.0
3.0 5.0
4.0 4.0
5.0 5.0

现在,创建最终的 R² 计算程序:

nano r_squared_print.c

输入以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// 计算线性回归参数的函数
void calculateRegressionParameters(double *x, double *y, int n,
                                   double *slope, double *intercept) {
    double sum_x = 0, sum_y = 0, sum_xy = 0, sum_x_squared = 0;

    for (int i = 0; i < n; i++) {
        sum_x += x[i];
        sum_y += y[i];
        sum_xy += x[i] * y[i];
        sum_x_squared += x[i] * x[i];
    }

    // 使用最小二乘法计算斜率和截距
    *slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x_squared - sum_x * sum_x);
    *intercept = (sum_y - *slope * sum_x) / n;
}

// 计算 R 平方的函数
double computeRSquared(double *x, double *y, int n, double slope, double intercept) {
    double total_variation = 0.0;
    double explained_variation = 0.0;
    double y_mean = 0.0;

    // 计算 y 的均值
    for (int i = 0; i < n; i++) {
        y_mean += y[i];
    }
    y_mean /= n;

    // 计算变差
    for (int i = 0; i < n; i++) {
        total_variation += pow(y[i] - y_mean, 2);
        double predicted_y = slope * x[i] + intercept;
        explained_variation += pow(y[i] - predicted_y, 2);
    }

    // 计算 R 平方
    return 1 - (explained_variation / total_variation);
}

// 解释 R 平方值的函数
void interpretRSquared(double r_squared) {
    printf("\nR² 解释:\n");
    if (r_squared < 0.3) {
        printf("模型拟合较差:该模型解释的方差小于 30%%。\n");
    } else if (r_squared < 0.5) {
        printf("模型拟合中等:该模型解释 30 - 50%%的方差。\n");
    } else if (r_squared < 0.7) {
        printf("模型拟合良好:该模型解释 50 - 70%%的方差。\n");
    } else {
        printf("模型拟合优秀:该模型解释超过 70%%的方差。\n");
    }
}

int main() {
    FILE *file;
    int n = 0, max_lines = 100;
    double x[100], y[100];
    double slope, intercept, r_squared;

    // 打开数据文件
    file = fopen("regression_data.txt", "r");
    if (file == NULL) {
        printf("打开文件错误!\n");
        return 1;
    }

    // 从文件读取数据
    while (fscanf(file, "%lf %lf", &x[n], &y[n]) == 2) {
        n++;
        if (n >= max_lines) break;
    }
    fclose(file);

    // 计算回归参数
    calculateRegressionParameters(x, y, n, &slope, &intercept);

    // 计算 R 平方
    r_squared = computeRSquared(x, y, n, slope, intercept);

    // 输出结果
    printf("回归分析结果:\n");
    printf("数据点数量:%d\n", n);
    printf("斜率:%.4f\n", slope);
    printf("截距:%.4f\n", intercept);
    printf("R 平方 (R²): %.4f\n", r_squared);

    // 解释 R 平方
    interpretRSquared(r_squared);

    return 0;
}

编译程序:

gcc -o r_squared_print r_squared_print.c -lm

运行程序:

./r_squared_print

示例输出:

回归分析结果:
数据点数量: 5
斜率: 0.6000
截距: 1.5000
R平方 (R²): 0.5600

R² 解释:
模型拟合良好: 该模型解释50 - 70%的方差。

关键点:

  1. 从外部文件读取数据
  2. 使用最小二乘法计算回归参数
  3. 计算 R² 值
  4. 提供 R² 值的解释
  5. 有助于理解模型的预测能力

总结

在本实验中,我们学习了如何在 C 语言中使用简单线性回归模型计算预测的 y 值。我们创建了一个程序,该程序接收 x 和 y 数据点以及回归线的斜率和截距,然后计算预测的 y 值。关键步骤包括根据回归方程计算预测的 y 值,然后输出原始 y 值和预测 y 值以进行比较。

接下来,我们将学习如何使用数据的解释变差和总变差来计算决定系数(R²)。