如何使用NNLS进行非负多元线性回归?

时间:2017-12-31 09:03:16

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

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

令我困惑的是,以下方法的界面看起来很奇怪。 我认为False是MxN矩阵,A是M向量,参数bata应分别是NxN矩阵和N向量。 但是,atb的实际类型为ata

double[]

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

2 个答案:

答案 0 :(得分:1)

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

你看看Spark 2.1.1的private[spark] object NNLS { 做了你想做的事情,但是从the latest Spark 2.2.1 marked as private[spark]开始就不是这样了。

org.apache.spark.mllib

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

  

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

     

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

换句话说,你应该远离包裹,特别是ata

那么有哪些替代方案?

您可以查看dgemv的测试,例如NNLSSuite,您可以找到答案。

  

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

这是一个矩阵,所以元素再次翻倍。事实上,y := alpha*A*x + beta*y, or y := alpha*A**T*x + beta*y, 会直接传递给here文档中描述的BLAS的NNLShereLAPACK):

  

DGEMV执行矩阵向量运算之一

NNLS
     

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

这应该给你足够的答案。

另一个问题是Spark MLlib推荐的true方式 - 就像计算一样?

它看起来像Spark MLLib的ALS算法uses NNLS(对机器学习从业者而言可能并不令人惊讶)。

当ALS配置为训练启用了nonnegative参数的模型时,即使用static_assert(sizeof(float) == sizeof(uint32_t)); static_assert(sizeof(double) == sizeof(uint64_t)); std::string as_binary_string( float value ) { std::uint32_t t; std::memcpy(&t, &value, sizeof(value)); return std::bitset<sizeof(float) * 8>(t).to_string(); } std::string as_binary_string( double value ) { std::uint64_t t; std::memcpy(&t, &value, sizeof(value)); return std::bitset<sizeof(double) * 8>(t).to_string(); } (默认情况下禁用)时,会使用该部分代码。

  

非负 Param是否应用非负性约束。

     

默认值:false

     

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

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

答案 1 :(得分:0)

我写了一个测试代码。 虽然我收到了Failed to load implementation from: com.github.fommil.netlib.NativeSystemBLAS之类的警告,但它适用于简单案例,但beta非常大(约3000)时m经常变为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);
    }
}