📄 logistic.java
字号:
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* Logistic.java
* Copyright (C) 2003 Xin Xu
*
*/
package weka.classifiers.functions;
import weka.classifiers.*;
import java.util.*;
import java.io.*;
import weka.core.*;
import weka.filters.*;
import weka.filters.unsupervised.attribute.*;
/**
* Second implementation for building and using a multinomial logistic
* regression model with a ridge estimator. <p>
*
* There are some modifications, however, compared to the paper of le
* Cessie and van Houwelingen(1992): <br>
*
* If there are k classes for n instances with m attributes, the
* parameter matrix B to be calculated will be an m*(k-1) matrix.<br>
*
* The probability for class j except the last class is <br>
* Pj(Xi) = exp(XiBj)/((sum[j=1..(k-1)]exp(Xi*Bj))+1) <br>
* The last class has probability <br>
* 1-(sum[j=1..(k-1)]Pj(Xi)) = 1/((sum[j=1..(k-1)]exp(Xi*Bj))+1) <br>
*
* The (negative) multinomial log-likelihood is thus: <br>
* L = -sum[i=1..n]{
* sum[j=1..(k-1)](Yij * ln(Pj(Xi))) +
* (1 - (sum[j=1..(k-1)]Yij)) * ln(1 - sum[j=1..(k-1)]Pj(Xi))
* } + ridge * (B^2) <br>
*
* In order to find the matrix B for which L is minimised, a
* Quasi-Newton Method is used to search for the optimized values of
* the m*(k-1) variables. Note that before we use the optimization
* procedure, we "squeeze" the matrix B into a m*(k-1) vector. For
* details of the optimization procedure, please check
* weka.core.Optimization class. <p>
*
* Although original Logistic Regression does not deal with instance
* weights, we modify the algorithm a little bit to handle the
* instance weights. <p>
*
* Reference: le Cessie, S. and van Houwelingen, J.C. (1992). <i>
* Ridge Estimators in Logistic Regression.</i> Applied Statistics,
* Vol. 41, No. 1, pp. 191-201. <p>
*
* Missing values are replaced using a ReplaceMissingValuesFilter, and
* nominal attributes are transformed into numeric attributes using a
* NominalToBinaryFilter.<p>
*
* Valid options are:<p>
*
* -D <br>
* Turn on debugging output.<p>
*
* -R <ridge> <br>
* Set the ridge parameter for the log-likelihood.<p>
*
* -M <number of iterations> <br> Set the maximum number of iterations
* (default -1, iterates until convergence).<p>
*
* @author Xin Xu (xx5@cs.waikato.ac.nz)
* @version $Revision: 1.1 $ */
public class Logistic extends Classifier
implements OptionHandler, WeightedInstancesHandler {
/** The coefficients (optimized parameters) of the model */
protected double [][] m_Par;
/** The data saved as a matrix */
protected double [][] m_Data;
/** The number of attributes in the model */
protected int m_NumPredictors;
/** The index of the class attribute */
protected int m_ClassIndex;
/** The number of the class labels */
protected int m_NumClasses;
/** The ridge parameter. */
protected double m_Ridge = 1e-8;
/* An attribute filter */
private RemoveUseless m_AttFilter;
/** The filter used to make attributes numeric. */
private NominalToBinary m_NominalToBinary;
/** The filter used to get rid of missing values. */
private ReplaceMissingValues m_ReplaceMissingValues;
/** Debugging output */
protected boolean m_Debug;
/** Log-likelihood of the searched model */
protected double m_LL;
/** The maximum number of iterations. */
private int m_MaxIts = -1;
/**
* Returns a string describing this classifier
* @return a description of the classifier suitable for
* displaying in the explorer/experimenter gui
*/
public String globalInfo() {
return "Class for building and using a multinomial logistic "
+"regression model with a ridge estimator.\n\n"
+"There are some modifications, however, compared to the paper of "
+"leCessie and van Houwelingen(1992): \n\n"
+"If there are k classes for n instances with m attributes, the "
+"parameter matrix B to be calculated will be an m*(k-1) matrix.\n\n"
+"The probability for class j with the exception of the last class is\n\n"
+"Pj(Xi) = exp(XiBj)/((sum[j=1..(k-1)]exp(Xi*Bj))+1) \n\n"
+"The last class has probability\n\n"
+"1-(sum[j=1..(k-1)]Pj(Xi)) \n\t= 1/((sum[j=1..(k-1)]exp(Xi*Bj))+1)\n\n"
+"The (negative) multinomial log-likelihood is thus: \n\n"
+"L = -sum[i=1..n]{\n\tsum[j=1..(k-1)](Yij * ln(Pj(Xi)))"
+"\n\t+(1 - (sum[j=1..(k-1)]Yij)) \n\t* ln(1 - sum[j=1..(k-1)]Pj(Xi))"
+"\n\t} + ridge * (B^2)\n\n"
+"In order to find the matrix B for which L is minimised, a "
+"Quasi-Newton Method is used to search for the optimized values of "
+"the m*(k-1) variables. Note that before we use the optimization "
+"procedure, we 'squeeze' the matrix B into a m*(k-1) vector. For "
+"details of the optimization procedure, please check "
+"weka.core.Optimization class.\n\n"
+"Although original Logistic Regression does not deal with instance "
+"weights, we modify the algorithm a little bit to handle the "
+"instance weights.\n\n"
+"For more information see:\n\nle Cessie, S. and van Houwelingen, J.C. (1992). "
+"Ridge Estimators in Logistic Regression. Applied Statistics, "
+"Vol. 41, No. 1, pp. 191-201. \n\n"
+"Note: Missing values are replaced using a ReplaceMissingValuesFilter, and "
+"nominal attributes are transformed into numeric attributes using a "
+"NominalToBinaryFilter.";
}
/**
* Returns an enumeration describing the available options
*
* @return an enumeration of all the available options
*/
public Enumeration listOptions() {
Vector newVector = new Vector(3);
newVector.addElement(new Option("\tTurn on debugging output.",
"D", 0, "-D"));
newVector.addElement(new Option("\tSet the ridge in the log-likelihood.",
"R", 1, "-R <ridge>"));
newVector.addElement(new Option("\tSet the maximum number of iterations"+
" (default -1, until convergence).",
"M", 1, "-M <number>"));
return newVector.elements();
}
/**
* Parses a given list of options. Valid options are:<p>
*
* -D <br>
* Turn on debugging output.<p>
*
* -R ridge <br>
* Set the ridge parameter for the log-likelihood.<p>
*
* -M num <br>
* Set the maximum number of iterations.
* (default -1, until convergence)<p>
*
* @param options the list of options as an array of strings
* @exception Exception if an option is not supported
*/
public void setOptions(String[] options) throws Exception {
setDebug(Utils.getFlag('D', options));
String ridgeString = Utils.getOption('R', options);
if (ridgeString.length() != 0)
m_Ridge = Double.parseDouble(ridgeString);
else
m_Ridge = 1.0e-8;
String maxItsString = Utils.getOption('M', options);
if (maxItsString.length() != 0)
m_MaxIts = Integer.parseInt(maxItsString);
else
m_MaxIts = -1;
}
/**
* Gets the current settings of the classifier.
*
* @return an array of strings suitable for passing to setOptions
*/
public String [] getOptions() {
String [] options = new String [5];
int current = 0;
if (getDebug())
options[current++] = "-D";
options[current++] = "-R";
options[current++] = ""+m_Ridge;
options[current++] = "-M";
options[current++] = ""+m_MaxIts;
while (current < options.length)
options[current++] = "";
return options;
}
/**
* Returns the tip text for this property
* @return tip text for this property suitable for
* displaying in the explorer/experimenter gui
*/
public String debugTipText() {
return "Output debug information to the console.";
}
/**
* Sets whether debugging output will be printed.
*
* @param debug true if debugging output should be printed
*/
public void setDebug(boolean debug) {
m_Debug = debug;
}
/**
* Gets whether debugging output will be printed.
*
* @return true if debugging output will be printed
*/
public boolean getDebug() {
return m_Debug;
}
/**
* Returns the tip text for this property
* @return tip text for this property suitable for
* displaying in the explorer/experimenter gui
*/
public String ridgeTipText() {
return "Set the Ridge value in the log-likelihood.";
}
/**
* Sets the ridge in the log-likelihood.
*
* @param ridge the ridge
*/
public void setRidge(double ridge) {
m_Ridge = ridge;
}
/**
* Gets the ridge in the log-likelihood.
*
* @return the ridge
*/
public double getRidge() {
return m_Ridge;
}
/**
* Returns the tip text for this property
* @return tip text for this property suitable for
* displaying in the explorer/experimenter gui
*/
public String maxItsTipText() {
return "Maximum number of iterations to perform.";
}
/**
* Get the value of MaxIts.
*
* @return Value of MaxIts.
*/
public int getMaxIts() {
return m_MaxIts;
}
/**
* Set the value of MaxIts.
*
* @param newMaxIts Value to assign to MaxIts.
*/
public void setMaxIts(int newMaxIts) {
m_MaxIts = newMaxIts;
}
private class OptEng extends Optimization{
// Weights of instances in the data
private double[] weights;
// Class labels of instances
private int[] cls;
/* Set the weights of instances
* @param d the weights to be set
*/
public void setWeights(double[] w) {
weights = w;
}
/* Set the class labels of instances
* @param d the class labels to be set
*/
public void setClassLabels(int[] c) {
cls = c;
}
/**
* Evaluate objective function
* @param x the current values of variables
* @return the value of the objective function
*/
protected double objectiveFunction(double[] x){
double nll = 0; // -LogLikelihood
int dim = m_NumPredictors+1; // Number of variables per class
for(int i=0; i<cls.length; i++){ // ith instance
double[] exp = new double[m_NumClasses-1];
int index;
for(int offset=0; offset<m_NumClasses-1; offset++){
index = offset * dim;
for(int j=0; j<dim; j++)
exp[offset] += m_Data[i][j]*x[index + j];
}
double max = exp[Utils.maxIndex(exp)];
double denom = Math.exp(-max);
double num;
if (cls[i] == m_NumClasses - 1) { // Class of this instance
num = -max;
} else {
num = exp[cls[i]] - max;
}
for(int offset=0; offset<m_NumClasses-1; offset++){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -