m_LLn = 0;
    public void buildClassifier(Instances train) throws Exception {		if (train.classAttribute().type() != Attribute.NOMINAL) {	    throw new Exception("Class attribute must be nominal.");	}	if (train.checkForStringAttributes()) {	    throw new Exception("Can't handle string attributes!");	}	train = new Instances(train);	train.deleteWithMissingClass();	if (train.numInstances() == 0) {	    throw new Exception("No train instances without missing class value!");	}	m_ReplaceMissingValues = new ReplaceMissingValuesFilter();	m_ReplaceMissingValues.setInputFormat(train);	train = Filter.useFilter(train, m_ReplaceMissingValues);	m_NominalToBinary = new NominalToBinaryFilter();	m_NominalToBinary.setInputFormat(train);	train = Filter.useFilter(train, m_NominalToBinary);	m_ClassIndex = train.classIndex();	m_NumClasses = train.numClasses();		int nK = m_NumClasses - 1;                     // Only K-1 class labels needed 	int nR = m_NumPredictors = train.numAttributes() - 1;	int nC = train.numInstances();		double [][] X  = new double [nC][nR + 1];       // Data values	double [][] Y  = new double [nC][nK];           // Class values	double [] xMean= new double [nR + 1];           // Attribute means	double [] xSD  = new double [nR + 1];           // Attribute stddev's	double [] sY = new double [nK + 1];             // Number of classes		if (m_Debug) {	    System.out.println("Extracting data...");	}		for (int s=0; s < nR+1; s++){	    xMean[s] = 0;	    xSD[s] = 0;	}	for(int t=0; t < nK+1; t++)	    sY[t] = 0;	for (int i = 0; i < X.length; i++) {	    // initialize X[][]	    Instance current = train.instance(i);	    int trueClass = (int)current.classValue();  // Class value starts from 0	  	    X[i][0] = 1;	    int j = 1;	    for (int k = 0; k <= nR; k++) {		if (k != m_ClassIndex) {		    double x = current.value(k);		    X[i][j] = x;		    xMean[j] = xMean[j] + x;		    xSD[j] = xSD[j] + x*x;		    j++;		}	    }	    	    // Class count, initialize Y[][]	    for (int l = 0; l < nK; l++){			if (l == trueClass){		    Y[i][l] = 1;		    sY[l] = sY[l]+1;		}		else		    Y[i][l] = 0;	    }	    if(trueClass == nK)		sY[nK] = sY[nK]+1;   	}		xMean[0] = 0; xSD[0] = 1;	for (int j = 1; j <= nR; j++) {	    xMean[j] = xMean[j] / nC;	    xSD[j] = xSD[j] / nC;	    xSD[j] = Math.sqrt(Math.abs( xSD[j] - xMean[j] * xMean[j]));	}	if (m_Debug) {	    	    // Output stats about input data	    System.out.println("Descriptives...");	    for (int m = 0; m <= nK; m++)		System.out.println(sY[m] + " cases have class " + m);	    System.out.println("\n Variable     Avg       SD    ");	    for (int j = 1; j <= nR; j++) 		System.out.println(Utils.doubleToString(j,8,4) 				   + Utils.doubleToString(xMean[j], 10, 4) 				   + Utils.doubleToString(xSD[j], 10, 4)				   );	}		// Normalise input data and remove ignored attributes	for (int i = 0; i < nC; i++) {	    for (int j = 0; j <= nR; j++) {		if (xSD[j] != 0) {		    X[i][j] = (X[i][j] - xMean[j]) / xSD[j];		}	    }	}		if (m_Debug) {	    System.out.println("\nIteration History..." );	}	m_Par = new double [nR + 1][nK];   // Coefficients	double LLp = 2e+10;                // Log-likelihood on previous iteration	m_LL  = 1e+10;                     // Log-likelihood of current iteration	m_LLn = 0;                         // Log-likelihood of null hypothesis		// Set up parameters for null model	for (int j = 0; j < m_Par.length; j++){ 		    for (int k = 0; k < nK; k++){			if (j == 0)		    m_Par[j][k] = Math.log((sY[k]+1) / (sY[nK]+1));		else		    m_Par[j][k] = 0;	    }	}		double x[][] = new double[nR + 1][nK];	for (int q=0; q < x.length;q++)	    for (int r=0; r < nK; r++)		x[q][r] = m_Par[q][r];		newtn(x, x.length, nK, X, Y);		if (m_Debug)	    System.out.println(" -------------<Converged>--------------");		// Convert coefficients back to non-normalized attribute units	for(int i=0; i < nK; i++){	    for(int j = 1; j <= nR; j++) {		if (xSD[j] != 0) {		    m_Par[j][i] /= xSD[j];		    m_Par[0][i] -= m_Par[j][i] * xMean[j];		}	    }	}    }		