【问题标题】:Java - sometimes return NaN when calculating Mahalanobis distanceJava - 计算马氏距离时有时会返回 NaN
【发布时间】:2017-09-11 05:38:04
【问题描述】:

我使用 org.apache.mahout.common.distance.MahalanobisDistanceMeasure 来计算矩阵中的行与平均向量之间的距离,但它有时会返回 NaN。我尝试调试,似乎在 Object 类中抛出了 NullPointerException。但对于其他行,一切都很好。如果有人能给我一些指导,我将不胜感激。

import com.opencsv.CSVReader;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

import com.opencsv.CSVWriter;
import org.apache.commons.math.MathException;
import org.apache.mahout.common.distance.MahalanobisDistanceMeasure;
import org.apache.mahout.math.*;
import org.apache.mahout.math.Matrix;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.stat.correlation.Covariance;
import org.apache.commons.math.distribution.ChiSquaredDistributionImpl;

public class FindMultivariateOutliers {
    public static void main(String[] args) {
        String url = "VIC_20160401_201606301.csv";
        double[][] data = extractRealData(readCSV(url), 3);
        double[][] dataSet = new double[30][49];
        for (int i = 30; i < 60; i++) {
            dataSet[i-30] = data[i];
        }

        double[] mean = calculateMeanVector(dataSet);
        Vector meanVector = new DenseVector(mean);
        Matrix covarianceMatrix = covarianceMatrix(dataSet);

        MahalanobisDistanceMeasure measure = new MahalanobisDistanceMeasure();
        measure.setMeanVector(meanVector);
        measure.setCovarianceMatrix(covarianceMatrix);

        for (int i = 0; i < dataSet.length; i++) {
            DenseVector ve = new DenseVector(dataSet[i]);
            double x = measure.distance(dataSet[centroid(dataSet)[0]][centroid(dataSet)[1]],meanVector,ve);
            System.out.println(i+" "+x);
        }
}

输出:

0 NaN
1 NaN
2 1.3382137932701006
3 5.140281428741069
4 5.448118335171329
5 4.658774790167001
6 3.055235041048766
7 5.577659807980593
8 2.9899726295069784
9 6.095988936666251
10 5.188517209151716
11 3.2929774499538014
12 5.090550175124932
13 5.801822265633947
14 4.714239296215186
15 5.02905587450129
16 4.981122780626051
17 5.195044166268684
18 5.325097238194922
19 4.7899888250142375
20 5.506442897174045
21 5.266585564849615
22 5.403384368592266
23 4.110229775894713
24 5.960687924915147
25 4.5745629099807745
26 5.0580441561885205
27 5.146058878694013
28 5.1375323540721425
29 3.7919178679466015

centroid()是一种计算矩阵质心的方法,返回int[2](第一个元素是x坐标,第二个元素是y)。 dataSet 是我关注的矩阵。

【问题讨论】:

  • 你能提供一个可验证的例子吗?您的程序正在从文件中读取数据,很遗憾我们没有该文件。也许只是提取有问题的数据集并将其放入代码中?
  • @LukeLee 数据有 49 个维度,因此很难提供示例。我更新了我的代码输出,你可以看看。
  • 如果您不清楚NaN 代表什么与正/负无穷大不同,您应该停下来阅读What Every Computer Scientist Should Know About Floating-Point Arithmetic。然后查看Javadoc中Double.NaNDouble.POSITIVE_INFINITYDouble.NEGATIVE_INFINITY的定义。提示:NaN 定义为0.0d/0.0d
  • @JimGarrison 谢谢吉姆,我会阅读链接并仔细检查我的代码。

标签: java nullpointerexception mahalanobis


【解决方案1】:

“NaN”代表“非数字”。如果浮点运算(Double/Float)有一些输入参数会导致运算产生一些未定义的结果,则会产生“Nan”。例如,0.0 除以 0.0 在算术上是未定义的。取负数的平方根也是未定义的。

NaN 是 Double 和 Float 包装类中的静态变量。它不是数值,因此在您的场景中,当您尝试测量两个坐标之间的距离时,它会返回 Double.NaN,然后​​它会尝试将其转换为基元编号,所以它会给你一个 NullPointerException。

【讨论】:

  • 原始浮点数可以很好地保存 NaN 值,不会抛出 NPE。
  • 这是否意味着有一些代码片段计算了 double/0.0 所以这个 NaN 出现在输出中?
  • @JimGarrison 当我执行我的代码时没有抛出异常,但是当我进入 Object 类时,它表明抛出了 NullPointerException 但它仍然继续执行。
  • @simons 它必须是 0.0/0.0;如果它计算 X/0.0,其中 X 不为零,则结果将是 Inf 或 -Inf(无穷大),而不是 NaN。此外,除了 0/0 之外,还有其他操作会产生 NaN。
  • @ajb 谢谢 ajb,我会进一步查看库,看看我的数据有什么问题。
猜你喜欢
  • 2015-06-25
  • 1970-01-01
  • 2019-08-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
  • 2018-06-29
相关资源
最近更新 更多