You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#回归线绘制结果与Python偏差,请求排查问题原因

问题排查:C#回归代码偏差原因分析

Python代码生成的回归线图表能保留刻度比例,回归线贴合更多数据点,准确性更高;而C#代码生成的图表结果存在明显偏差。以下是两段实现代码,我们来排查C#代码的问题:

Python代码

# Fit2.py
import numpy as np

def ReadDataFromFile(data_file_path):
    """
    Reads data from a file assuming two columns of numbers, separated by whitespace.
    Returns two lists, one for x-values and one for y-values.
    """
    with open(data_file_path, 'r') as file:
        lines = file.readlines()

    x_values = []
    y_values = []

    for line in lines:
        parts = line.strip().split()
        if len(parts) == 2:
            x_values.append(float(parts[0]))
            y_values.append(float(parts[1]))

    return x_values, y_values

def CreateRegressionLine(x_values, y_values):
    """
    Creates a regression line based on log-log transformed data.
    Returns two lists containing the log-space points of the regression line.
    """
    log_x_values = np.log(x_values)
    log_y_values = np.log(y_values)

    # Fit the regression using np.polyfit for a first degree polynomial, which is a linear fit
    slope, intercept = np.polyfit(log_x_values, log_y_values, 1)

    # Create the regression line in log space
    regression_log_y_values = slope * log_x_values + intercept

    # Convert the regression line back to linear space
    regression_y_values = np.exp(regression_log_y_values)

    return x_values, regression_y_values.tolist()

C#代码

public static class Fit2
{
    public static Tuple<List<double>, List<double>> ReadDataFromFile(string filePath)
    {
        var xList = new List<double>();
        var yList = new List<double>();

        foreach (var line in File.ReadAllLines(filePath))
        {
            if (line.StartsWith("#")) continue; // Skip the comment lines

            var parts = line.Split('\t');
            if (parts.Length == 2)
            {
                if (double.TryParse(parts[0], out var x) && double.TryParse(parts[1], out var y))
                {
                    xList.Add(x);
                    yList.Add(y);
                }
            }
        }

        return Tuple.Create(xList, yList);
    }

    public static Tuple<double, double> CalculateLinearRegressionCoefficients(double[] xValues, double[] yValues)
    {
        if (xValues.Length != yValues.Length)
        {
            throw new ArgumentException("Input arrays must have the same length.");
        }

        var (a, b) = SimpleRegression.Fit(xValues, yValues);
        return Tuple.Create(a, b);
    }

    public static Tuple<List<double>, List<double>> CreateRegressionLine(List<double> xList, List<double> yList)
    {
        var xValues = xList.ToArray();
        var yValues = yList.ToArray();
        var coefficients = CalculateLinearRegressionCoefficients(xValues, yValues);

        var xVals = new List<double> { xValues.First(), xValues.Last() };
        var yVals = xVals.Select(x => coefficients.Item1 + coefficients.Item2 * x).ToList();

        return Tuple.Create(xVals, yVals);
    }
}

核心问题分析

对比两段代码的实现逻辑,C#代码存在三个关键错误:

  1. 缺少对数转换步骤
    Python实现的是对数-对数空间的线性回归(用于拟合幂律关系):先对x、y取自然对数,在对数空间拟合直线,再通过指数转换回原线性空间,这是处理这类数据的标准方法。而C#直接对原始x、y值做线性回归,完全跳过了对数转换,这是导致回归线偏差的核心原因。

  2. 回归线生成方式错误
    Python用所有输入的x值计算对应的回归y值,生成的是贴合全量数据的曲线;C#仅取x的首尾两个点计算y值,画的是两点直线,即使回归逻辑正确,也无法体现数据的整体趋势,更无法贴合中间数据点。

  3. 数据读取的潜在兼容性问题
    Python用任意空白字符分割数据(空格、制表符都支持),而C#仅用制表符\t分割。如果数据文件是用空格分隔的,C#会读取不到有效数据,进一步导致回归结果错误。

修正后的C#代码示例

using System;
using System.Collections.Generic;
using System.Linq;
using MathNet.Numerics.Statistics; // 需要引用MathNet.Numerics库

public static class Fit2
{
    public static Tuple<List<double>, List<double>> ReadDataFromFile(string filePath)
    {
        var xList = new List<double>();
        var yList = new List<double>();

        foreach (var line in File.ReadAllLines(filePath))
        {
            if (line.StartsWith("#")) continue;

            // 改用任意空白分割,和Python保持一致
            var parts = line.Trim().Split(new[] {' ', '\t'}, StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length == 2)
            {
                if (double.TryParse(parts[0], out var x) && double.TryParse(parts[1], out var y))
                {
                    xList.Add(x);
                    yList.Add(y);
                }
            }
        }

        return Tuple.Create(xList, yList);
    }

    public static Tuple<double, double> CalculateLogLogRegressionCoefficients(List<double> xList, List<double> yList)
    {
        if (xList.Count != yList.Count)
        {
            throw new ArgumentException("Input lists must have the same length.");
        }

        // 对x、y取自然对数
        var logX = xList.Select(Math.Log).ToArray();
        var logY = yList.Select(Math.Log).ToArray();

        // 在对数空间拟合线性回归
        var regression = SimpleRegression.Fit(logX, logY);
        // regression.Item1是截距,Item2是斜率
        return Tuple.Create(regression.Item1, regression.Item2);
    }

    public static Tuple<List<double>, List<double>> CreateRegressionLine(List<double> xList, List<double> yList)
    {
        var coefficients = CalculateLogLogRegressionCoefficients(xList, yList);
        var intercept = coefficients.Item1;
        var slope = coefficients.Item2;

        // 用所有x值计算回归y值(转换回原空间)
        var regressionY = xList.Select(x => Math.Exp(intercept + slope * Math.Log(x))).ToList();

        return Tuple.Create(xList, regressionY);
    }
}

内容的提问来源于stack exchange,提问作者user366312

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:54:50