如何使用 LINQ 在 C# 中实现梯度下降算法?

Posted

技术标签:

【中文标题】如何使用 LINQ 在 C# 中实现梯度下降算法?【英文标题】:How to implement Gradient Descent algorithm in C# using LINQ? 【发布时间】:2022-01-04 12:46:48 【问题描述】:

目标是为简单的线性回归创建梯度下降算法。有很多具有多行代码的解决方案。如何避免给定示例中的嵌套 for 循环?

double[] x = new double[]  1, 2, 3, 4 ;
double[] y = new double[]  5, 7, 9, 12 ;

double slope_current = 0;
double intercept_current = 0;
double slope_derivative = 0;
double intercept_derivative = 0;
double learningRate = 0.01;
int iterations = 1500;

for (int i = 0; i < iterations; i++)

    for (int j = 0; j < x.Length; j++)
    
        double y_pred = (slope_current * x[j]) + intercept_current;
        intercept_derivative += (1.0 / x.Length) * (y_pred - y[j]);
        slope_derivative += (1.0 / x.Length) * (y_pred - y[j]) * x[j];
    

    intercept_current = intercept_current - learningRate * intercept_derivative;
    slope_current = slope_current - learningRate * slope_derivative;

我想使用 LINQ 创建一个更紧凑的版本。

【问题讨论】:

我会问 - 为什么?使用嵌套的 for 循环,代码更具可读性。如果将 (1.0 / x.Length) * (y_pred - y[j]) 重构为单独的变量,它的可读性会更高。 是的,那样会更易读。但我很好奇 LINQ ***者的解决方案。 【参考方案1】:

可以使用 LINQ 将 for 循环替换为 SumZip 函数。

double[] x = new double[]  1, 2, 3, 4 ;
double[] y = new double[]  5, 7, 9, 12 ;

double slope_current = 0;
double intercept_current = 0;
double learningRate = 0.01;
int iterations = 5000;

for (int i = 0; i < iterations; i++)

    double intercept_derivative = (1.0 / x.Length) * x.Zip(y, (x_i, y_i) => (slope_current * x_i + intercept_current) - y_i).Sum();
    double slope_derivative = (1.0 / x.Length) * x.Zip(y, (x_i, y_i) => ((slope_current * x_i + intercept_current) - y_i) * x_i).Sum();

    slope_current = slope_current - learningRate * slope_derivative;
    intercept_current = intercept_current - learningRate * intercept_derivative;

【讨论】:

以上是关于如何使用 LINQ 在 C# 中实现梯度下降算法?的主要内容,如果未能解决你的问题,请参考以下文章

梯度下降算法在 Haskell 中不收敛

随机梯度下降实现 - MATLAB

.NET(C#) System.Linq中实现多列group by(分组)的示例代码

在 C# LINQ 中实现 RANK OVER SQL 子句

Java中梯度下降逻辑回归的实现

梯度下降算法