用Java重新了混合高斯分类。
写完测试用Vectors.dense( 1.0,2.0,3.0 ), Vectors.dense( 2.0,2.0,3.0 ),Vectors.dense( 3.0,2.0,3.0 )做测试,参数为 TestGaussianMixture gaussian = new TestGaussianMixture( 2, 0.01,2,10);然后看model中的weights。
测试结果为5.5951692130668595E-8, 0.9999999440483078,可是用GaussianMixture计算结果5.5951692130668595E-8,0.9999999440483078
结果不一样,因为我机器不能调试scala代码,直接看,看了一遍又一遍,几天也不知道错在哪里。然后用反射一个一个替换写的方法,还是没有头绪。然后给GaussianMixture设置初始的model(和我们计算的一样),突然GaussianMixture计算结果就是5.5951692130668595E-8, 0.9999999440483078,问题就出在初始化的model上。
初始化就两个方法,都没有问题,但是当用反射的方法替代vectorMean 方法时,得到了正确的值。又仔细看了一遍,代码没有问题,是损失了精度。
原来的代码为
private static Vector vectorMean( List<Vector> list )
{
int size = list.size( );
Vector retValue = Vectors.zeros( list.get( 0 ).size( ) );
for ( Vector v : list )
{
BLAS.axpy( 1.0, v, retValue );
}
BLAS.scal( 1.0 / size, retValue );
return retValue;
}
在计算scal的时候14/5 = 2.8000000003,用反射调用GaussianMixture的这个方法时就是2.8.
然后改成
private static Vector vectorMean( List<Vector> list )
{
int size = list.size( );
Vector retValue = Vectors.zeros( list.get( 0 ).size( ) );
for ( Vector v : list )
{
BLAS.axpy( 1.0, v, retValue );
}
double[] ds = retValue.toArray( );
for (int i=0; i< ds.length; i++)
{
ds[i] = div( ds[i], size, 1 );
}
return retValue;
}
private static double div(double d1,double d2,int scale)
{
BigDecimal b1=new BigDecimal(Double.toString(d1));
BigDecimal b2=new BigDecimal(Double.toString(d2));
return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
结果就正确了。
过程几乎什么都怀疑了,但是问题就出在这个简单的方法上。
源代码如下
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.spark.SparkContext;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.broadcast.Broadcast;
import org.apache.spark.mllib.linalg.BLAS;
import org.apache.spark.mllib.linalg.DenseMatrix;
import org.apache.spark.mllib.linalg.Matrices;
import org.apache.spark.mllib.linalg.Matrix;
import org.apache.spark.mllib.linalg.Vector;
import org.apache.spark.mllib.linalg.Vectors;
import org.apache.spark.mllib.stat.distribution.MultivariateGaussian;
import org.apache.spark.mllib.util.MLUtils$;
import org.apache.spark.rdd.RDD;
import scala.Array;
import scala.Tuple2;
import scala.Tuple3;
import scala.collection.JavaConverters;
import scala.reflect.ClassManifestFactory;
import scala.runtime.AbstractFunction0;
import scala.runtime.AbstractFunction1;
import scala.runtime.AbstractFunction2;
/**
*
*/
public class GaoGaussianMixture implements Serializable
{
private int k;
private double convergenceTol;
private int maxIterations;
private long seed;
private int nSamples = 5;
public GaoGaussianMixture()
{
this(2, 0.01, 100, new Random().nextInt( ));
}
public GaoGaussianMixture( int k, double convergenceTol, int maxIterations, long seed )
{
super( );
this.k = k;
this.convergenceTol = convergenceTol;
this.maxIterations = maxIterations;
this.seed = seed;
}
public GaoGaussianMixtureModel run( JavaRDD<Vector> data )
{
retur