【问题标题】:How to use NNLS for non-negative multiple linear regression?如何使用 NNLS 进行非负多元线性回归?
【发布时间】:2018-06-10 23:53:23
【问题描述】:

我正在尝试解决 Java 中的非负多元线性回归问题。 我发现了一个用 Scala 编写的求解器类org.apache.spark.mllib.optimization.NNLS。 但是,我不知道如何使用它。

让我困惑的是,下面这个方法的界面看起来很奇怪。 我认为A 是MxN 矩阵,b 是M 向量,而参数ata 和atb 应该分别是NxN 矩阵和N 向量。 但是,ata 的实际类型是 double[]。

public static double[] solve(double[] ata, double[] atb, NNLS.Workspace ws)

我搜索了示例代码,但找不到。 谁能给我一个示例代码? 该库是用 Scala 编写的,但如果可能的话,我想要 Java 代码。

【问题讨论】:

    标签: java apache-spark linear-regression apache-spark-mllib


    【解决方案1】:

    我写了一个测试代码。 虽然我收到了一些像Failed to load implementation from: com.github.fommil.netlib.NativeSystemBLAS 这样的警告,但它适用于简单的情况,但是当m 非常大(大约3000)时,beta 通常会变为0。

    package test;
    
    import org.apache.spark.mllib.optimization.NNLS;
    
    public class NNLSTest {
        public static void main(String[] args) {
            int n = 6, m = 300;
            ExampleInMatLabDoc();
            AllPositiveBetaNoiseInY(n, m);
            SomeNegativesInBeta(n, m);
            NoCorrelation(n, m);
        }
    
        private static void test(double[][] X, double[] y, double[] b) {        
            int m = X.length; int n = X[0].length;
    
            double[] Xty = new double[n];
            for (int i = 0; i < n; i++) {
                Xty[i] = 0.0;
                for (int j = 0; j < m; j++) Xty[i] += X[j][i] * y[j];
            }
            double[] XtX = new double[n * n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    XtX[n * i + j] = 0.0;
                    for (int k = 0; k < m; k++) XtX[n * i + j] += X[k][i] * X[k][j];
                }
            }
    
            double[] beta = NNLS.solve(XtX, Xty, NNLS.createWorkspace(n));
            System.out.println("\ntrue beta\tbeta");
            for (int i = 0; i < beta.length; i++) System.out.println(b[i] + "\t" + beta[i]);
    
        }
    
        private static void ExampleInMatLabDoc() {
            // https://jp.mathworks.com/help/matlab/ref/lsqnonneg.html
            double[] y = new double[] { 0.8587, 0.1781, 0.0747, 0.8405 };
            double[][] x = new double[4][];
            x[0] = new double[] { 0.0372, 0.2869 };
            x[1] = new double[] { 0.6861, 0.7071 };
            x[2] = new double[] { 0.6233, 0.6245 };
            x[3] = new double[] { 0.6344, 0.6170 };
            double[] b = new double[] { 0.0, 0.6929 };
            test(x, y, b);
        }
    
        private static void AllPositiveBetaNoiseInY(int n, int m) {
            double[] b = new double[n];
            for (int i = 0; i < n; i++) b[i] = Math.random() * 100.0;       // random value in [0:100]
            double[] y = new double[m];
            double[][] x = new double[m][];
            for (int i = 0; i < m; i++) {
                x[i] = new double[n];
                x[i][0] = 1.0;
                y[i] = b[0];
                for (int j = 1; j < n; j++) {
                    x[i][j] = (2.0 * Math.random() - 1.0) * 100.0; // random value in [-100:100]
                    y[i] += x[i][j] * b[j];
                }
                y[i] *= 1.0 + (2.0 * Math.random() - 1.0) * 0.1; // add noise
            }
            test(x, y, b);
        }
    
        private static void SomeNegativesInBeta(int n, int m) {
            double[] b = new double[n];
            for (int i = 0; i < n; i++) b[i] = (2.0 * Math.random() - 1.0) * 100.0; // random value in [-100:100]
            double[] y = new double[m];
            double[][] x = new double[m][];
            for (int i = 0; i < m; i++) {
                x[i] = new double[n];
                x[i][0] = 1.0;
                y[i] = b[0];
                for (int j = 1; j < n; j++) {
                    x[i][j] = (2.0 * Math.random() - 1.0) * 100.0; // random value in [-100:100]
                    y[i] += x[i][j] * b[j];
                }
            }
            test(x, y, b);
        }
    
        private static void NoCorrelation(int n, int m) {
            double[] y = new double[m];
            double[][] x = new double[m][];
            for (int i = 0; i < m; i++) {
                x[i] = new double[n];
                x[i][0] = 1.0;
                for (int j = 1; j < n; j++) 
                    x[i][j] = (2.0 * Math.random() - 1.0) * 100.0; // random value in [-100:100]
                y[i] = (2.0 * Math.random() - 1.0) * 100.0;
            }
            double[] b = new double[n];
            for (int i = 0; i < n; i++) b[i] = 0;
            test(x, y, b);
        }
    }
    

    【讨论】:

      【解决方案2】:

      免责声明我从未使用过NNLS,也不知道非负多元线性回归。

      您可以查看 Spark 2.1.1 的 NNLS,它可以满足您的需求,但自 the latest Spark 2.2.1 marked as private[spark] 以来就不是这样了。

      private[spark] object NNLS {
      

      更重要的是,从 Spark 2.0 开始,org.apache.spark.mllib 包(包括NNLS 所属的org.apache.spark.mllib.optimization)在maintenance mode 中:

      基于 MLlib RDD 的 API 现在处于维护模式。

      从 Spark 2.0 开始,spark.mllib 包中基于 RDD 的 API 已进入维护模式。 Spark 的主要机器学习 API 现在是 spark.ml 包中基于 DataFrame 的 API。

      换句话说,你应该远离包裹,尤其是NNLS。

      那么有什么选择呢?

      您可以查看NNLS 的测试,即NNLSSuite,在那里您可以找到一些答案。

      但是,ata 的实际类型是 double[]。

      这是一个矩阵,所以元素再次加倍。事实上,ata 直接传递给 BLAS 的 dgemv(here 和 here),在 LAPACK 文档中有所描述:

      DGEMV 执行矩阵向量运算之一

      y := alpha*A*x + beta*y,   or   y := alpha*A**T*x + beta*y,
      

      其中 alpha 和 beta 是标量,x 和 y 是向量,A 是 m乘n矩阵。

      这应该会给你足够的答案。


      另一个问题是 Spark MLlib 中推荐的 NNLS 类计算方法是什么?

      它看起来就像是 Spark MLLib 的 ALS 算法 uses NNLS (这对于机器学习从业者来说可能并不奇怪)。

      当 ALS 配置为在 nonnegative 参数打开的情况下训练模型时使用该部分代码,即 true(默认情况下禁用)。

      nonnegative 是否应用非负约束的参数。

      默认值:假

      最小二乘是否使用非负约束

      我建议查看 Spark MLlib 的这一部分,以更深入地了解 NNLS 用于解决非负线性回归问题的用途。

      【讨论】:

      • 感谢您的详细描述。 In other words, you should stay away from the package and NNLS in particular. 那么,我现在不应该使用 NNLS 吗?无论如何,我阅读了NNLSSuite 并发现ata 被扁平化了。我写了一些测试代码,它似乎运行良好。所以我会在下面发布。
      • “那么,我现在不应该使用 NNLS 吗?” 似乎是这样。如果有帮助,请接受答案(或至少投票)。这将帮助其他人找到对你有帮助的东西。谢谢!
      猜你喜欢
      • 1970-01-01
      • 2019-09-18
      • 2018-08-11
      • 2013-07-14
      • 2016-04-19
      • 1970-01-01
      • 1970-01-01
      • 2021-03-11
      • 1970-01-01
      相关资源
      最近更新 更多