如何使用 NNLS 进行非负多元线性回归?
How to use NNLS for non-negative multiple linear regression?
我正在尝试解决 Java 中的非负多元线性回归问题。
我找到了一个用 Scala 编写的求解器 class 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 代码。
免责声明我从未使用过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:
The MLlib RDD-based API is now in maintenance mode.
As of Spark 2.0, the RDD-based APIs in the spark.mllib package have entered maintenance mode. The primary Machine Learning API for Spark is now the DataFrame-based API in the spark.ml package.
换句话说,你应该远离包裹,尤其是NNLS
。
那有什么选择呢?
您可以查看 NNLS
的测试,即 NNLSSuite,在那里您可以找到一些答案。
However, the actual type of ata is double[].
这是一个矩阵,所以元素又是双倍的。事实上,ata
直接传递给 BLAS 的 dgemv
(here and here) that is described in the LAPACK docs:
DGEMV performs one of the matrix-vector operations
y := alpha*A*x + beta*y, or y := alpha*A**T*x + beta*y,
where alpha and beta are scalars, x and y are vectors and A is an
m by n matrix.
这应该会给你足够的答案。
另一个问题是 Spark MLlib 中推荐的 NNLS
类计算方式是什么?
看起来像是 Spark MLLib 的 ALS 算法 uses NNLS
在幕后(这对于机器学习从业者来说可能并不奇怪)。
当 ALS 配置为训练模型并打开 nonnegative 参数时使用该部分代码,即 true
(默认情况下禁用)。
nonnegative Param for whether to apply nonnegativity constraints.
Default: false
whether to use nonnegative constraint for least squares
我建议复习 Spark MLlib 的那一部分,以更深入地了解 NNLS
用于解决非负线性回归问题的用途。
我写了一个测试代码。
虽然我得到了一些像 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);
}
}
我正在尝试解决 Java 中的非负多元线性回归问题。
我找到了一个用 Scala 编写的求解器 class 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 代码。
免责声明我从未使用过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:
The MLlib RDD-based API is now in maintenance mode.
As of Spark 2.0, the RDD-based APIs in the spark.mllib package have entered maintenance mode. The primary Machine Learning API for Spark is now the DataFrame-based API in the spark.ml package.
换句话说,你应该远离包裹,尤其是NNLS
。
那有什么选择呢?
您可以查看 NNLS
的测试,即 NNLSSuite,在那里您可以找到一些答案。
However, the actual type of ata is double[].
这是一个矩阵,所以元素又是双倍的。事实上,ata
直接传递给 BLAS 的 dgemv
(here and here) that is described in the LAPACK docs:
DGEMV performs one of the matrix-vector operations
y := alpha*A*x + beta*y, or y := alpha*A**T*x + beta*y,
where alpha and beta are scalars, x and y are vectors and A is an m by n matrix.
这应该会给你足够的答案。
另一个问题是 Spark MLlib 中推荐的 NNLS
类计算方式是什么?
看起来像是 Spark MLLib 的 ALS 算法 uses NNLS
在幕后(这对于机器学习从业者来说可能并不奇怪)。
当 ALS 配置为训练模型并打开 nonnegative 参数时使用该部分代码,即 true
(默认情况下禁用)。
nonnegative Param for whether to apply nonnegativity constraints.
Default: false
whether to use nonnegative constraint for least squares
我建议复习 Spark MLlib 的那一部分,以更深入地了解 NNLS
用于解决非负线性回归问题的用途。
我写了一个测试代码。
虽然我得到了一些像 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);
}
}