使用C# / .Net实现高效的多元线性回归

16

有人知道在C#中进行多元线性回归的高效方法吗?其中同时方程的数量可能达到1000个(带有3或4个不同的输入)。在阅读这篇文章关于多元线性回归之后,我尝试使用矩阵方程式实现它:

Matrix y = new Matrix(
    new double[,]{{745},
                  {895},
                  {442},
                  {440},
                  {1598}});

Matrix x = new Matrix(
     new double[,]{{1, 36, 66},
                 {1, 37, 68},
                 {1, 47, 64},
                 {1, 32, 53},
                 {1, 1, 101}});

Matrix b = (x.Transpose() * x).Inverse() * x.Transpose() * y;

for (int i = 0; i < b.Rows; i++)
{
  Trace.WriteLine("INFO: " + b[i, 0].ToDouble());
}

然而,由于矩阵反演操作,它无法很好地适应1000个方程的规模。我可以调用R语言并使用它,但是我希望有一个纯.NET解决方案,可以扩展到这些大型集合。
有什么建议吗?
编辑#1:
我暂时使用了R。通过使用statconn(从此处下载),我发现这种方法既快速又相对容易使用。也就是说,这是一个小的代码片段,使用R statconn库并不需要太多的代码(注意:这不是所有的代码!)。
_StatConn.EvaluateNoReturn(string.Format("output <- lm({0})", equation));
object intercept = _StatConn.Evaluate("coefficients(output)['(Intercept)']");
parameters[0] = (double)intercept;
for (int i = 0; i < xColCount; i++)
{
  object parameter = _StatConn.Evaluate(string.Format("coefficients(output)['x{0}']", i));
  parameters[i + 1] = (double)parameter;
}

你是指想让矩阵操作更快吗?我不认为这将是最好的方法,我认为最好的方法是使用非矩阵风格的方法(或者避免使用逆运算)。 - mike
我在http://www.codeproject.com/KB/recipes/LinReg.aspx上取得了成功。非常易于使用,而且是开源的! - David Talbot
6个回答

3

值得一提的是,我最近发现了ALGLIB库,它虽然没有太多的文档说明,但是有一些非常有用的函数,比如线性回归,这也是我需要的东西之一。

以下是示例代码(此代码旧且未经验证,只是我使用ALGLIB库的基本示例)。我在时间序列上使用线性回归,其中包含3个条目(称为3min/2min/1min),然后是最终值(Final)。

public void Foo(List<Sample> samples)
{
  int nAttributes = 3; // 3min, 2min, 1min
  int nSamples = samples.Count;
  double[,] tsData = new double[nSamples, nAttributes];
  double[] resultData = new double[nSamples];

  for (int i = 0; i < samples.Count; i++)
  {
    tsData[i, 0] = samples[i].Tminus1min;
    tsData[i, 1] = samples[i].Tminus2min;
    tsData[i, 2] = samples[i].Tminus3min;

    resultData[i] = samples[i].Final;
  }

  double[] weights = null;
  int fitResult = 0;
  alglib.lsfit.lsfitreport rep = new alglib.lsfit.lsfitreport();
  alglib.lsfit.lsfitlinear(resultData, tsData, nSamples, nAttributes, ref fitResult, ref weights, rep);

  Dictionary<string, double> labelsAndWeights = new Dictionary<string, double>();
  labelsAndWeights.Add("1min", weights[0]);
  labelsAndWeights.Add("2min", weights[1]);
  labelsAndWeights.Add("3min", weights[2]);
}

好的建议。您愿意发布任何代码示例吗? - Mario
请参考以下示例代码(您需要引用alglib),希望它仍然有效。 - mike
1
不错。你会如何将一个未知的常量变量加入到这个示例中? - Oriental

2

我通常使用 Math.Net Numerics 进行线性回归。

Math.NET Numerics旨在为科学、工程和日常使用中的数值计算提供方法和算法。涵盖的主题包括特殊函数、线性代数、概率模型、随机数、插值、积分、回归、优化问题等。

例如,如果您想使用线性回归将数据拟合到一条直线上,只需执行以下操作:

double[] xdata = new double[] { 10, 20, 30 };
double[] ydata = new double[] { 15, 20, 25 };
Tuple"<"double, double">" p = Fit.Line(xdata, ydata);
double a = p.Item1; // == 10; intercept
double b = p.Item2; // == 0.5; slope

2

矩阵的大小不随同时方程(样本)的数量增加而增加。 x.转置() * x 是一个方阵,其维度为独立变量的数量。


有趣的点,那我想知道我的性能为什么会下降这么多呢?我的数据集大约有6000个样本。我需要进一步调查这个问题。 - mike
我猜你的性能下降是因为x.Transpose() * x在处理更大的矩阵时需要更多时间。我有一个库可以处理数百万个数据点......如果你感兴趣,我会尝试找出来。我大约20年前遇到了这个问题(是的,我很老),并找到了一个巧妙的数学解决方案 :-) - Joe H
1
如果你想要更好的缩放效果,应该使用梯度下降法。 - Win Coder

1

我建议使用FinMath。它是一个极其优化的 .net 数值计算库。它使用英特尔数学核心库进行复杂计算,如线性回归或矩阵求逆,但大多数类都有非常简单易懂的接口。当然,它也可以扩展到大量数据集。

using FinMath.LeastSquares;
using FinMath.LinearAlgebra;

Vector y = new Vector(new double[]{745,
    895,
    442,
    440,
    1598});

Matrix X = new Matrix(new double[,]{
    {1, 36, 66},
    {1, 37, 68},
    {1, 47, 64},
    {1, 32, 53},
    {1, 1, 101}});

Vector b = OrdinaryLS.FitOLS(X, y);

Console.WriteLine(b);

1

尝试使用 Meta.Numerics

Meta.Numerics 是一个用于 .NET Framework 中高级科学计算的库。它可以从 C#、Visual Basic、F# 或任何其他 .NET 编程语言中使用。Meta.Numerics 库是完全面向对象的,并针对实现和执行速度进行了优化。

要填充矩阵,请查看ColumnVector Constructor (IList<Double>) 的示例。它可以从许多有序的实数集合(包括 double[] 和 List)构建 ColumnVector


谢谢,我之前没见过这个库。看起来不错,但仍然存在使用矩阵解方程的问题。我认为我需要采用不同的方法。 - mike

0
我最近发现了一个名为MathNet-Numerics的开源项目,使用MIT许可证。
它声称提供了一种更快的方式来替代通常的(X.Transpose() * X).Inverse() * (X.Transpose() * y)过程。
这里有一些文章中的优化方法,第一个如下:
X.TransposeThisAndMultiply(X).Inverse() * X.TransposeThisAndMultiply(y)

或者,您可以使用Cholesky分解

X.TransposeThisAndMultiply(X).Cholesky().Solve(X.TransposeThisAndMultiply(y))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接