我试图解决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代码。
免责声明我从未使用过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
包(包括org.apache.spark.mllib.optimization
所属的NNLS
)位于maintenance mode:
基于MLlib RDD的API现在处于维护模式。
从Spark 2.0开始,spark.mllib包中基于RDD的API已进入维护模式。 Spark的主要机器学习API现在是spark.ml包中基于DataFrame的API。
换句话说,你应该远离包裹,尤其是NNLS
。
那么有什么选择呢?
您可以查看NNLS
的测试,即NNLSSuite,在那里您可以找到一些答案。
但是,ata的实际类型是double []。
这是一个矩阵,所以元素再次翻倍。事实上,ata
直接传递给了dgemv
文档中描述的BLAS的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
(默认情况下禁用)时,将使用该部分代码。
非负Param是否应用非负性约束。
默认值:false
是否对最小二乘使用非负约束
我建议回顾一下Spark MLlib的那部分,以深入了解NNLS
用于解决非负线性回归问题的用法。
我写了一个测试代码。虽然我收到了像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);
}
}