m_ClassIndex = train.classIndex();
  public void buildClassifier(Instances train) throws Exception {    if (train.classAttribute().type() != Attribute.NOMINAL) {      throw new Exception("Class attribute must be nominal.");    }    if (train.classAttribute().numValues() != 2) {      throw new Exception("Only 2-class problems allowed.");    }    if (train.checkForStringAttributes()) {      throw new Exception("Can't handle string attributes!");    }    m_ClassIndex = train.classIndex();    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.inputFormat(train);    train = Filter.useFilter(train, m_ReplaceMissingValues);    m_NominalToBinary = new NominalToBinaryFilter();    m_NominalToBinary.inputFormat(train);    train = Filter.useFilter(train, m_NominalToBinary);    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];               // Class values    double [] xMean= new double [nR + 1];           // Attribute means    double [] xSD  = new double [nR + 1];           // Attribute stddev's    double sY0 = 0;                                 // Number of class 0    double sY1 = 0;                                 // Number of class 1    if (m_Debug) {      System.out.println("Extracting data...");    }    for (int i = 0; i < X.length; i++) {      Instance current = train.instance(i);      X[i][0] = 1;      int j = 1;      for (int k = 0; k <= nR; k++) {	if (k != m_ClassIndex) {	  double x = current.value(k);	  if ((i == j) && (i <= nR)) {	    x += 1e-8;	  }	  X[i][j] = x;	  xMean[j] = xMean[j] + x;	  xSD[j] = xSD[j] + x*x;	  j++;	}      }      Y[i] = current.classValue();      if (Y[i] != 0) {	Y[i] = 1;      }      if (Y[i] == 0) {	sY0 = sY0 + 1;      } else {	sY1 = sY1 + 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...");      System.out.println("" + sY0 + " cases have Y=0; " 			 + sY1 + " cases have Y=1.");      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];    // 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    double [] deltas = new double [nR + 1];    Matrix jacobian = new Matrix(nR + 1, nR + 1);    // Set up parameters for null model    m_Par[0] = Math.log((sY1+1) / (sY0+1));    for (int j = 1; j < m_Par.length; j++) {      m_Par[j] = 0;    }        // While the log-likelihood is changing (i.e. no maxima found)    while(Math.abs(LLp-m_LL) > 0.00001) {      LLp = m_LL;      m_LL = calculateLogLikelihood(X, Y, jacobian, deltas);      if (LLp == 1e+10) {	m_LLn = m_LL;       }      if (m_Debug) {	System.out.println("-2 Log Likelihood = " 			   + Utils.doubleToString(m_LL, 10, 5)			   + ((m_LLn == m_LL) ? " (Null Model)" : ""));      }            jacobian.lubksb(jacobian.ludcmp(), deltas);      // Adjust the coefficients      for (int j = 0; j < deltas.length; j++) {	m_Par[j] += deltas[j];      }    }    if (m_Debug) {      System.out.println(" (Converged)");    }    // Convert coefficients back to non-normalized attribute units    for(int j = 1; j <= nR; j++) {      if (xSD[j] != 0) {	m_Par[j] = m_Par[j] / xSD[j];	m_Par[0] = m_Par[0] - m_Par[j] * xMean[j];      }    }  }		