Source Code Cross Referenced for MISMO.java in  » Science » weka » weka » classifiers » mi » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Science » weka » weka.classifiers.mi 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *    This program is free software; you can redistribute it and/or modify
0003:         *    it under the terms of the GNU General Public License as published by
0004:         *    the Free Software Foundation; either version 2 of the License, or
0005:         *    (at your option) any later version.
0006:         *
0007:         *    This program is distributed in the hope that it will be useful,
0008:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0009:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0010:         *    GNU General Public License for more details.
0011:         *
0012:         *    You should have received a copy of the GNU General Public License
0013:         *    along with this program; if not, write to the Free Software
0014:         *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
0015:         */
0016:
0017:        /*
0018:         * MISMO.java
0019:         * Copyright (C) 2005 University of Waikato, Hamilton, New Zealand
0020:         *
0021:         */
0022:
0023:        package weka.classifiers.mi;
0024:
0025:        import weka.classifiers.Classifier;
0026:        import weka.classifiers.functions.Logistic;
0027:        import weka.classifiers.functions.supportVector.Kernel;
0028:        import weka.classifiers.functions.supportVector.SMOset;
0029:        import weka.classifiers.mi.supportVector.MIPolyKernel;
0030:        import weka.core.Attribute;
0031:        import weka.core.Capabilities;
0032:        import weka.core.FastVector;
0033:        import weka.core.Instance;
0034:        import weka.core.Instances;
0035:        import weka.core.MultiInstanceCapabilitiesHandler;
0036:        import weka.core.Option;
0037:        import weka.core.OptionHandler;
0038:        import weka.core.SelectedTag;
0039:        import weka.core.SerializedObject;
0040:        import weka.core.Tag;
0041:        import weka.core.TechnicalInformation;
0042:        import weka.core.TechnicalInformationHandler;
0043:        import weka.core.Utils;
0044:        import weka.core.WeightedInstancesHandler;
0045:        import weka.core.Capabilities.Capability;
0046:        import weka.core.TechnicalInformation.Field;
0047:        import weka.core.TechnicalInformation.Type;
0048:        import weka.filters.Filter;
0049:        import weka.filters.unsupervised.attribute.MultiInstanceToPropositional;
0050:        import weka.filters.unsupervised.attribute.NominalToBinary;
0051:        import weka.filters.unsupervised.attribute.Normalize;
0052:        import weka.filters.unsupervised.attribute.PropositionalToMultiInstance;
0053:        import weka.filters.unsupervised.attribute.ReplaceMissingValues;
0054:        import weka.filters.unsupervised.attribute.Standardize;
0055:
0056:        import java.io.Serializable;
0057:        import java.util.Enumeration;
0058:        import java.util.Random;
0059:        import java.util.Vector;
0060:
0061:        /**
0062:         <!-- globalinfo-start -->
0063:         * Implements John Platt's sequential minimal optimization algorithm for training a support vector classifier.<br/>
0064:         * <br/>
0065:         * This implementation globally replaces all missing values and transforms nominal attributes into binary ones. It also normalizes all attributes by default. (In that case the coefficients in the output are based on the normalized data, not the original data --- this is important for interpreting the classifier.)<br/>
0066:         * <br/>
0067:         * Multi-class problems are solved using pairwise classification.<br/>
0068:         * <br/>
0069:         * To obtain proper probability estimates, use the option that fits logistic regression models to the outputs of the support vector machine. In the multi-class case the predicted probabilities are coupled using Hastie and Tibshirani's pairwise coupling method.<br/>
0070:         * <br/>
0071:         * Note: for improved speed normalization should be turned off when operating on SparseInstances.<br/>
0072:         * <br/>
0073:         * For more information on the SMO algorithm, see<br/>
0074:         * <br/>
0075:         * J. Platt: Machines using Sequential Minimal Optimization. In B. Schoelkopf and C. Burges and A. Smola, editors, Advances in Kernel Methods - Support Vector Learning, 1998.<br/>
0076:         * <br/>
0077:         * S.S. Keerthi, S.K. Shevade, C. Bhattacharyya, K.R.K. Murthy (2001). Improvements to Platt's SMO Algorithm for SVM Classifier Design. Neural Computation. 13(3):637-649.
0078:         * <p/>
0079:         <!-- globalinfo-end -->
0080:         *
0081:         <!-- technical-bibtex-start -->
0082:         * BibTeX:
0083:         * <pre>
0084:         * &#64;incollection{Platt1998,
0085:         *    author = {J. Platt},
0086:         *    booktitle = {Advances in Kernel Methods - Support Vector Learning},
0087:         *    editor = {B. Schoelkopf and C. Burges and A. Smola},
0088:         *    publisher = {MIT Press},
0089:         *    title = {Machines using Sequential Minimal Optimization},
0090:         *    year = {1998}
0091:         * }
0092:         * 
0093:         * &#64;article{Keerthi2001,
0094:         *    author = {S.S. Keerthi and S.K. Shevade and C. Bhattacharyya and K.R.K. Murthy},
0095:         *    journal = {Neural Computation},
0096:         *    number = {3},
0097:         *    pages = {637-649},
0098:         *    title = {Improvements to Platt's SMO Algorithm for SVM Classifier Design},
0099:         *    volume = {13},
0100:         *    year = {2001}
0101:         * }
0102:         * </pre>
0103:         * <p/>
0104:         <!-- technical-bibtex-end -->
0105:         *
0106:         <!-- options-start -->
0107:         * Valid options are: <p/>
0108:         * 
0109:         * <pre> -D
0110:         *  If set, classifier is run in debug mode and
0111:         *  may output additional info to the console</pre>
0112:         * 
0113:         * <pre> -no-checks
0114:         *  Turns off all checks - use with caution!
0115:         *  Turning them off assumes that data is purely numeric, doesn't
0116:         *  contain any missing values, and has a nominal class. Turning them
0117:         *  off also means that no header information will be stored if the
0118:         *  machine is linear. Finally, it also assumes that no instance has
0119:         *  a weight equal to 0.
0120:         *  (default: checks on)</pre>
0121:         * 
0122:         * <pre> -C &lt;double&gt;
0123:         *  The complexity constant C. (default 1)</pre>
0124:         * 
0125:         * <pre> -N
0126:         *  Whether to 0=normalize/1=standardize/2=neither.
0127:         *  (default 0=normalize)</pre>
0128:         * 
0129:         * <pre> -I
0130:         *  Use MIminimax feature space. </pre>
0131:         * 
0132:         * <pre> -L &lt;double&gt;
0133:         *  The tolerance parameter. (default 1.0e-3)</pre>
0134:         * 
0135:         * <pre> -P &lt;double&gt;
0136:         *  The epsilon for round-off error. (default 1.0e-12)</pre>
0137:         * 
0138:         * <pre> -M
0139:         *  Fit logistic models to SVM outputs. </pre>
0140:         * 
0141:         * <pre> -V &lt;double&gt;
0142:         *  The number of folds for the internal cross-validation. 
0143:         *  (default -1, use training data)</pre>
0144:         * 
0145:         * <pre> -W &lt;double&gt;
0146:         *  The random number seed. (default 1)</pre>
0147:         * 
0148:         * <pre> -K &lt;classname and parameters&gt;
0149:         *  The Kernel to use.
0150:         *  (default: weka.classifiers.functions.supportVector.PolyKernel)</pre>
0151:         * 
0152:         * <pre> 
0153:         * Options specific to kernel weka.classifiers.mi.supportVector.MIPolyKernel:
0154:         * </pre>
0155:         * 
0156:         * <pre> -D
0157:         *  Enables debugging output (if available) to be printed.
0158:         *  (default: off)</pre>
0159:         * 
0160:         * <pre> -no-checks
0161:         *  Turns off all checks - use with caution!
0162:         *  (default: checks on)</pre>
0163:         * 
0164:         * <pre> -C &lt;num&gt;
0165:         *  The size of the cache (a prime number).
0166:         *  (default: 250007)</pre>
0167:         * 
0168:         * <pre> -E &lt;num&gt;
0169:         *  The Exponent to use.
0170:         *  (default: 1.0)</pre>
0171:         * 
0172:         * <pre> -L
0173:         *  Use lower-order terms.
0174:         *  (default: no)</pre>
0175:         * 
0176:         <!-- options-end -->
0177:         *
0178:         * @author Eibe Frank (eibe@cs.waikato.ac.nz)
0179:         * @author Shane Legg (shane@intelligenesis.net) (sparse vector code)
0180:         * @author Stuart Inglis (stuart@reeltwo.com) (sparse vector code)
0181:         * @author Lin Dong (ld21@cs.waikato.ac.nz) (code for adapting to MI data)
0182:         * @version $Revision: 1.4 $ 
0183:         */
0184:        public class MISMO extends Classifier implements 
0185:                WeightedInstancesHandler, MultiInstanceCapabilitiesHandler,
0186:                TechnicalInformationHandler {
0187:
0188:            /** for serialization */
0189:            static final long serialVersionUID = -5834036950143719712L;
0190:
0191:            /**
0192:             * Returns a string describing classifier
0193:             * @return a description suitable for
0194:             * displaying in the explorer/experimenter gui
0195:             */
0196:            public String globalInfo() {
0197:
0198:                return "Implements John Platt's sequential minimal optimization "
0199:                        + "algorithm for training a support vector classifier.\n\n"
0200:                        + "This implementation globally replaces all missing values and "
0201:                        + "transforms nominal attributes into binary ones. It also "
0202:                        + "normalizes all attributes by default. (In that case the coefficients "
0203:                        + "in the output are based on the normalized data, not the "
0204:                        + "original data --- this is important for interpreting the classifier.)\n\n"
0205:                        + "Multi-class problems are solved using pairwise classification.\n\n"
0206:                        + "To obtain proper probability estimates, use the option that fits "
0207:                        + "logistic regression models to the outputs of the support vector "
0208:                        + "machine. In the multi-class case the predicted probabilities "
0209:                        + "are coupled using Hastie and Tibshirani's pairwise coupling "
0210:                        + "method.\n\n"
0211:                        + "Note: for improved speed normalization should be turned off when "
0212:                        + "operating on SparseInstances.\n\n"
0213:                        + "For more information on the SMO algorithm, see\n\n"
0214:                        + getTechnicalInformation().toString();
0215:            }
0216:
0217:            /**
0218:             * Returns an instance of a TechnicalInformation object, containing 
0219:             * detailed information about the technical background of this class,
0220:             * e.g., paper reference or book this class is based on.
0221:             * 
0222:             * @return the technical information about this class
0223:             */
0224:            public TechnicalInformation getTechnicalInformation() {
0225:                TechnicalInformation result;
0226:                TechnicalInformation additional;
0227:
0228:                result = new TechnicalInformation(Type.INCOLLECTION);
0229:                result.setValue(Field.AUTHOR, "J. Platt");
0230:                result.setValue(Field.YEAR, "1998");
0231:                result.setValue(Field.TITLE,
0232:                        "Machines using Sequential Minimal Optimization");
0233:                result.setValue(Field.BOOKTITLE,
0234:                        "Advances in Kernel Methods - Support Vector Learning");
0235:                result.setValue(Field.EDITOR,
0236:                        "B. Schoelkopf and C. Burges and A. Smola");
0237:                result.setValue(Field.PUBLISHER, "MIT Press");
0238:
0239:                additional = result.add(Type.ARTICLE);
0240:                additional
0241:                        .setValue(Field.AUTHOR,
0242:                                "S.S. Keerthi and S.K. Shevade and C. Bhattacharyya and K.R.K. Murthy");
0243:                additional.setValue(Field.YEAR, "2001");
0244:                additional
0245:                        .setValue(Field.TITLE,
0246:                                "Improvements to Platt's SMO Algorithm for SVM Classifier Design");
0247:                additional.setValue(Field.JOURNAL, "Neural Computation");
0248:                additional.setValue(Field.VOLUME, "13");
0249:                additional.setValue(Field.NUMBER, "3");
0250:                additional.setValue(Field.PAGES, "637-649");
0251:
0252:                return result;
0253:            }
0254:
0255:            /**
0256:             * Class for building a binary support vector machine.
0257:             */
0258:            protected class BinaryMISMO implements  Serializable {
0259:
0260:                /** for serialization */
0261:                static final long serialVersionUID = -7107082483475433531L;
0262:
0263:                /** The Lagrange multipliers. */
0264:                protected double[] m_alpha;
0265:
0266:                /** The thresholds. */
0267:                protected double m_b, m_bLow, m_bUp;
0268:
0269:                /** The indices for m_bLow and m_bUp */
0270:                protected int m_iLow, m_iUp;
0271:
0272:                /** The training data. */
0273:                protected Instances m_data;
0274:
0275:                /** Weight vector for linear machine. */
0276:                protected double[] m_weights;
0277:
0278:                /** Variables to hold weight vector in sparse form.
0279:                  (To reduce storage requirements.) */
0280:                protected double[] m_sparseWeights;
0281:                protected int[] m_sparseIndices;
0282:
0283:                /** Kernel to use **/
0284:                protected Kernel m_kernel;
0285:
0286:                /** The transformed class values. */
0287:                protected double[] m_class;
0288:
0289:                /** The current set of errors for all non-bound examples. */
0290:                protected double[] m_errors;
0291:
0292:                /* The five different sets used by the algorithm. */
0293:                /** {i: 0 < m_alpha[i] < C} */
0294:                protected SMOset m_I0;
0295:                /** {i: m_class[i] = 1, m_alpha[i] = 0} */
0296:                protected SMOset m_I1;
0297:                /** {i: m_class[i] = -1, m_alpha[i] = C} */
0298:                protected SMOset m_I2;
0299:                /** {i: m_class[i] = 1, m_alpha[i] = C} */
0300:                protected SMOset m_I3;
0301:                /** {i: m_class[i] = -1, m_alpha[i] = 0} */
0302:                protected SMOset m_I4;
0303:
0304:                /** The set of support vectors {i: 0 < m_alpha[i]} */
0305:                protected SMOset m_supportVectors;
0306:
0307:                /** Stores logistic regression model for probability estimate */
0308:                protected Logistic m_logistic = null;
0309:
0310:                /** Stores the weight of the training instances */
0311:                protected double m_sumOfWeights = 0;
0312:
0313:                /**
0314:                 * Fits logistic regression model to SVM outputs analogue
0315:                 * to John Platt's method.  
0316:                 *
0317:                 * @param insts the set of training instances
0318:                 * @param cl1 the first class' index
0319:                 * @param cl2 the second class' index
0320:                 * @param numFolds the number of folds for cross-validation
0321:                 * @param random the random number generator for cross-validation
0322:                 * @throws Exception if the sigmoid can't be fit successfully
0323:                 */
0324:                protected void fitLogistic(Instances insts, int cl1, int cl2,
0325:                        int numFolds, Random random) throws Exception {
0326:
0327:                    // Create header of instances object
0328:                    FastVector atts = new FastVector(2);
0329:                    atts.addElement(new Attribute("pred"));
0330:                    FastVector attVals = new FastVector(2);
0331:                    attVals.addElement(insts.classAttribute().value(cl1));
0332:                    attVals.addElement(insts.classAttribute().value(cl2));
0333:                    atts.addElement(new Attribute("class", attVals));
0334:                    Instances data = new Instances("data", atts, insts
0335:                            .numInstances());
0336:                    data.setClassIndex(1);
0337:
0338:                    // Collect data for fitting the logistic model
0339:                    if (numFolds <= 0) {
0340:
0341:                        // Use training data
0342:                        for (int j = 0; j < insts.numInstances(); j++) {
0343:                            Instance inst = insts.instance(j);
0344:                            double[] vals = new double[2];
0345:                            vals[0] = SVMOutput(-1, inst);
0346:                            if (inst.classValue() == cl2) {
0347:                                vals[1] = 1;
0348:                            }
0349:                            data.add(new Instance(inst.weight(), vals));
0350:                        }
0351:                    } else {
0352:
0353:                        // Check whether number of folds too large
0354:                        if (numFolds > insts.numInstances()) {
0355:                            numFolds = insts.numInstances();
0356:                        }
0357:
0358:                        // Make copy of instances because we will shuffle them around
0359:                        insts = new Instances(insts);
0360:
0361:                        // Perform three-fold cross-validation to collect
0362:                        // unbiased predictions
0363:                        insts.randomize(random);
0364:                        insts.stratify(numFolds);
0365:                        for (int i = 0; i < numFolds; i++) {
0366:                            Instances train = insts
0367:                                    .trainCV(numFolds, i, random);
0368:                            SerializedObject so = new SerializedObject(this );
0369:                            BinaryMISMO smo = (BinaryMISMO) so.getObject();
0370:                            smo.buildClassifier(train, cl1, cl2, false, -1, -1);
0371:                            Instances test = insts.testCV(numFolds, i);
0372:                            for (int j = 0; j < test.numInstances(); j++) {
0373:                                double[] vals = new double[2];
0374:                                vals[0] = smo.SVMOutput(-1, test.instance(j));
0375:                                if (test.instance(j).classValue() == cl2) {
0376:                                    vals[1] = 1;
0377:                                }
0378:                                data.add(new Instance(
0379:                                        test.instance(j).weight(), vals));
0380:                            }
0381:                        }
0382:                    }
0383:
0384:                    // Build logistic regression model
0385:                    m_logistic = new Logistic();
0386:                    m_logistic.buildClassifier(data);
0387:                }
0388:
0389:                /**
0390:                 * sets the kernel to use
0391:                 * 
0392:                 * @param value	the kernel to use
0393:                 */
0394:                public void setKernel(Kernel value) {
0395:                    m_kernel = value;
0396:                }
0397:
0398:                /**
0399:                 * Returns the kernel to use
0400:                 * 
0401:                 * @return 		the current kernel
0402:                 */
0403:                public Kernel getKernel() {
0404:                    return m_kernel;
0405:                }
0406:
0407:                /**
0408:                 * Method for building the binary classifier.
0409:                 *
0410:                 * @param insts the set of training instances
0411:                 * @param cl1 the first class' index
0412:                 * @param cl2 the second class' index
0413:                 * @param fitLogistic true if logistic model is to be fit
0414:                 * @param numFolds number of folds for internal cross-validation
0415:                 * @param randomSeed seed value for random number generator for cross-validation
0416:                 * @throws Exception if the classifier can't be built successfully
0417:                 */
0418:                protected void buildClassifier(Instances insts, int cl1,
0419:                        int cl2, boolean fitLogistic, int numFolds,
0420:                        int randomSeed) throws Exception {
0421:
0422:                    // Initialize some variables
0423:                    m_bUp = -1;
0424:                    m_bLow = 1;
0425:                    m_b = 0;
0426:                    m_alpha = null;
0427:                    m_data = null;
0428:                    m_weights = null;
0429:                    m_errors = null;
0430:                    m_logistic = null;
0431:                    m_I0 = null;
0432:                    m_I1 = null;
0433:                    m_I2 = null;
0434:                    m_I3 = null;
0435:                    m_I4 = null;
0436:                    m_sparseWeights = null;
0437:                    m_sparseIndices = null;
0438:
0439:                    // Store the sum of weights
0440:                    m_sumOfWeights = insts.sumOfWeights();
0441:
0442:                    // Set class values
0443:                    m_class = new double[insts.numInstances()];
0444:                    m_iUp = -1;
0445:                    m_iLow = -1;
0446:                    for (int i = 0; i < m_class.length; i++) {
0447:                        if ((int) insts.instance(i).classValue() == cl1) {
0448:                            m_class[i] = -1;
0449:                            m_iLow = i;
0450:                        } else if ((int) insts.instance(i).classValue() == cl2) {
0451:                            m_class[i] = 1;
0452:                            m_iUp = i;
0453:                        } else {
0454:                            throw new Exception("This should never happen!");
0455:                        }
0456:                    }
0457:
0458:                    // Check whether one or both classes are missing
0459:                    if ((m_iUp == -1) || (m_iLow == -1)) {
0460:                        if (m_iUp != -1) {
0461:                            m_b = -1;
0462:                        } else if (m_iLow != -1) {
0463:                            m_b = 1;
0464:                        } else {
0465:                            m_class = null;
0466:                            return;
0467:                        }
0468:                        m_supportVectors = new SMOset(0);
0469:                        m_alpha = new double[0];
0470:                        m_class = new double[0];
0471:
0472:                        // Fit sigmoid if requested
0473:                        if (fitLogistic) {
0474:                            fitLogistic(insts, cl1, cl2, numFolds, new Random(
0475:                                    randomSeed));
0476:                        }
0477:                        return;
0478:                    }
0479:
0480:                    // Set the reference to the data
0481:                    m_data = insts;
0482:                    m_weights = null;
0483:
0484:                    // Initialize alpha array to zero
0485:                    m_alpha = new double[m_data.numInstances()];
0486:
0487:                    // Initialize sets
0488:                    m_supportVectors = new SMOset(m_data.numInstances());
0489:                    m_I0 = new SMOset(m_data.numInstances());
0490:                    m_I1 = new SMOset(m_data.numInstances());
0491:                    m_I2 = new SMOset(m_data.numInstances());
0492:                    m_I3 = new SMOset(m_data.numInstances());
0493:                    m_I4 = new SMOset(m_data.numInstances());
0494:
0495:                    // Clean out some instance variables
0496:                    m_sparseWeights = null;
0497:                    m_sparseIndices = null;
0498:
0499:                    // Initialize error cache
0500:                    m_errors = new double[m_data.numInstances()];
0501:                    m_errors[m_iLow] = 1;
0502:                    m_errors[m_iUp] = -1;
0503:
0504:                    // Initialize kernel
0505:                    m_kernel.buildKernel(m_data);
0506:
0507:                    // Build up I1 and I4
0508:                    for (int i = 0; i < m_class.length; i++) {
0509:                        if (m_class[i] == 1) {
0510:                            m_I1.insert(i);
0511:                        } else {
0512:                            m_I4.insert(i);
0513:                        }
0514:                    }
0515:
0516:                    // Loop to find all the support vectors
0517:                    int numChanged = 0;
0518:                    boolean examineAll = true;
0519:                    while ((numChanged > 0) || examineAll) {
0520:                        numChanged = 0;
0521:                        if (examineAll) {
0522:                            for (int i = 0; i < m_alpha.length; i++) {
0523:                                if (examineExample(i)) {
0524:                                    numChanged++;
0525:                                }
0526:                            }
0527:                        } else {
0528:
0529:                            // This code implements Modification 1 from Keerthi et al.'s paper
0530:                            for (int i = 0; i < m_alpha.length; i++) {
0531:                                if ((m_alpha[i] > 0)
0532:                                        && (m_alpha[i] < m_C
0533:                                                * m_data.instance(i).weight())) {
0534:                                    if (examineExample(i)) {
0535:                                        numChanged++;
0536:                                    }
0537:
0538:                                    // Is optimality on unbound vectors obtained?
0539:                                    if (m_bUp > m_bLow - 2 * m_tol) {
0540:                                        numChanged = 0;
0541:                                        break;
0542:                                    }
0543:                                }
0544:                            }
0545:
0546:                            //This is the code for Modification 2 from Keerthi et al.'s paper
0547:                            /*boolean innerLoopSuccess = true; 
0548:                              numChanged = 0;
0549:                              while ((m_bUp < m_bLow - 2 * m_tol) && (innerLoopSuccess == true)) {
0550:                              innerLoopSuccess = takeStep(m_iUp, m_iLow, m_errors[m_iLow]);
0551:                              }*/
0552:                        }
0553:
0554:                        if (examineAll) {
0555:                            examineAll = false;
0556:                        } else if (numChanged == 0) {
0557:                            examineAll = true;
0558:                        }
0559:                    }
0560:
0561:                    // Set threshold
0562:                    m_b = (m_bLow + m_bUp) / 2.0;
0563:
0564:                    // Save memory
0565:                    m_kernel.clean();
0566:
0567:                    m_errors = null;
0568:                    m_I0 = m_I1 = m_I2 = m_I3 = m_I4 = null;
0569:
0570:                    // Fit sigmoid if requested
0571:                    if (fitLogistic) {
0572:                        fitLogistic(insts, cl1, cl2, numFolds, new Random(
0573:                                randomSeed));
0574:                    }
0575:
0576:                }
0577:
0578:                /**
0579:                 * Computes SVM output for given instance.
0580:                 *
0581:                 * @param index the instance for which output is to be computed
0582:                 * @param inst the instance 
0583:                 * @return the output of the SVM for the given instance
0584:                 * @throws Exception if something goes wrong
0585:                 */
0586:                protected double SVMOutput(int index, Instance inst)
0587:                        throws Exception {
0588:
0589:                    double result = 0;
0590:
0591:                    for (int i = m_supportVectors.getNext(-1); i != -1; i = m_supportVectors
0592:                            .getNext(i)) {
0593:                        result += m_class[i] * m_alpha[i]
0594:                                * m_kernel.eval(index, i, inst);
0595:                    }
0596:                    result -= m_b;
0597:
0598:                    return result;
0599:                }
0600:
0601:                /**
0602:                 * Prints out the classifier.
0603:                 *
0604:                 * @return a description of the classifier as a string
0605:                 */
0606:                public String toString() {
0607:
0608:                    StringBuffer text = new StringBuffer();
0609:                    int printed = 0;
0610:
0611:                    if ((m_alpha == null) && (m_sparseWeights == null)) {
0612:                        return "BinaryMISMO: No model built yet.\n";
0613:                    }
0614:                    try {
0615:                        text.append("BinaryMISMO\n\n");
0616:
0617:                        for (int i = 0; i < m_alpha.length; i++) {
0618:                            if (m_supportVectors.contains(i)) {
0619:                                double val = m_alpha[i];
0620:                                if (m_class[i] == 1) {
0621:                                    if (printed > 0) {
0622:                                        text.append(" + ");
0623:                                    }
0624:                                } else {
0625:                                    text.append(" - ");
0626:                                }
0627:                                text.append(Utils.doubleToString(val, 12, 4)
0628:                                        + " * <");
0629:                                for (int j = 0; j < m_data.numAttributes(); j++) {
0630:                                    if (j != m_data.classIndex()) {
0631:                                        text.append(m_data.instance(i)
0632:                                                .toString(j));
0633:                                    }
0634:                                    if (j != m_data.numAttributes() - 1) {
0635:                                        text.append(" ");
0636:                                    }
0637:                                }
0638:                                text.append("> * X]\n");
0639:                                printed++;
0640:                            }
0641:                        }
0642:
0643:                        if (m_b > 0) {
0644:                            text.append(" - "
0645:                                    + Utils.doubleToString(m_b, 12, 4));
0646:                        } else {
0647:                            text.append(" + "
0648:                                    + Utils.doubleToString(-m_b, 12, 4));
0649:                        }
0650:
0651:                        text.append("\n\nNumber of support vectors: "
0652:                                + m_supportVectors.numElements());
0653:                        int numEval = 0;
0654:                        int numCacheHits = -1;
0655:                        if (m_kernel != null) {
0656:                            numEval = m_kernel.numEvals();
0657:                            numCacheHits = m_kernel.numCacheHits();
0658:                        }
0659:                        text.append("\n\nNumber of kernel evaluations: "
0660:                                + numEval);
0661:                        if (numCacheHits >= 0 && numEval > 0) {
0662:                            double hitRatio = 1 - numEval * 1.0
0663:                                    / (numCacheHits + numEval);
0664:                            text.append(" ("
0665:                                    + Utils
0666:                                            .doubleToString(hitRatio * 100, 7,
0667:                                                    3).trim() + "% cached)");
0668:                        }
0669:
0670:                    } catch (Exception e) {
0671:                        e.printStackTrace();
0672:
0673:                        return "Can't print BinaryMISMO classifier.";
0674:                    }
0675:
0676:                    return text.toString();
0677:                }
0678:
0679:                /**
0680:                 * Examines instance.
0681:                 *
0682:                 * @param i2 index of instance to examine
0683:                 * @return true if examination was successfull
0684:                 * @throws Exception if something goes wrong
0685:                 */
0686:                protected boolean examineExample(int i2) throws Exception {
0687:
0688:                    double y2, F2;
0689:                    int i1 = -1;
0690:
0691:                    y2 = m_class[i2];
0692:                    if (m_I0.contains(i2)) {
0693:                        F2 = m_errors[i2];
0694:                    } else {
0695:                        F2 = SVMOutput(i2, m_data.instance(i2)) + m_b - y2;
0696:                        m_errors[i2] = F2;
0697:
0698:                        // Update thresholds
0699:                        if ((m_I1.contains(i2) || m_I2.contains(i2))
0700:                                && (F2 < m_bUp)) {
0701:                            m_bUp = F2;
0702:                            m_iUp = i2;
0703:                        } else if ((m_I3.contains(i2) || m_I4.contains(i2))
0704:                                && (F2 > m_bLow)) {
0705:                            m_bLow = F2;
0706:                            m_iLow = i2;
0707:                        }
0708:                    }
0709:
0710:                    // Check optimality using current bLow and bUp and, if
0711:                    // violated, find an index i1 to do joint optimization
0712:                    // with i2...
0713:                    boolean optimal = true;
0714:                    if (m_I0.contains(i2) || m_I1.contains(i2)
0715:                            || m_I2.contains(i2)) {
0716:                        if (m_bLow - F2 > 2 * m_tol) {
0717:                            optimal = false;
0718:                            i1 = m_iLow;
0719:                        }
0720:                    }
0721:                    if (m_I0.contains(i2) || m_I3.contains(i2)
0722:                            || m_I4.contains(i2)) {
0723:                        if (F2 - m_bUp > 2 * m_tol) {
0724:                            optimal = false;
0725:                            i1 = m_iUp;
0726:                        }
0727:                    }
0728:                    if (optimal) {
0729:                        return false;
0730:                    }
0731:
0732:                    // For i2 unbound choose the better i1...
0733:                    if (m_I0.contains(i2)) {
0734:                        if (m_bLow - F2 > F2 - m_bUp) {
0735:                            i1 = m_iLow;
0736:                        } else {
0737:                            i1 = m_iUp;
0738:                        }
0739:                    }
0740:                    if (i1 == -1) {
0741:                        throw new Exception("This should never happen!");
0742:                    }
0743:                    return takeStep(i1, i2, F2);
0744:                }
0745:
0746:                /**
0747:                 * Method solving for the Lagrange multipliers for
0748:                 * two instances.
0749:                 *
0750:                 * @param i1 index of the first instance
0751:                 * @param i2 index of the second instance
0752:                 * @param F2
0753:                 * @return true if multipliers could be found
0754:                 * @throws Exception if something goes wrong
0755:                 */
0756:                protected boolean takeStep(int i1, int i2, double F2)
0757:                        throws Exception {
0758:
0759:                    double alph1, alph2, y1, y2, F1, s, L, H, k11, k12, k22, eta, a1, a2, f1, f2, v1, v2, Lobj, Hobj;
0760:                    double C1 = m_C * m_data.instance(i1).weight();
0761:                    double C2 = m_C * m_data.instance(i2).weight();
0762:
0763:                    // Don't do anything if the two instances are the same
0764:                    if (i1 == i2) {
0765:                        return false;
0766:                    }
0767:
0768:                    // Initialize variables
0769:                    alph1 = m_alpha[i1];
0770:                    alph2 = m_alpha[i2];
0771:                    y1 = m_class[i1];
0772:                    y2 = m_class[i2];
0773:                    F1 = m_errors[i1];
0774:                    s = y1 * y2;
0775:
0776:                    // Find the constraints on a2
0777:                    if (y1 != y2) {
0778:                        L = Math.max(0, alph2 - alph1);
0779:                        H = Math.min(C2, C1 + alph2 - alph1);
0780:                    } else {
0781:                        L = Math.max(0, alph1 + alph2 - C1);
0782:                        H = Math.min(C2, alph1 + alph2);
0783:                    }
0784:                    if (L >= H) {
0785:                        return false;
0786:                    }
0787:
0788:                    // Compute second derivative of objective function
0789:                    k11 = m_kernel.eval(i1, i1, m_data.instance(i1));
0790:                    k12 = m_kernel.eval(i1, i2, m_data.instance(i1));
0791:                    k22 = m_kernel.eval(i2, i2, m_data.instance(i2));
0792:                    eta = 2 * k12 - k11 - k22;
0793:
0794:                    // Check if second derivative is negative
0795:                    if (eta < 0) {
0796:
0797:                        // Compute unconstrained maximum
0798:                        a2 = alph2 - y2 * (F1 - F2) / eta;
0799:
0800:                        // Compute constrained maximum
0801:                        if (a2 < L) {
0802:                            a2 = L;
0803:                        } else if (a2 > H) {
0804:                            a2 = H;
0805:                        }
0806:                    } else {
0807:
0808:                        // Look at endpoints of diagonal
0809:                        f1 = SVMOutput(i1, m_data.instance(i1));
0810:                        f2 = SVMOutput(i2, m_data.instance(i2));
0811:                        v1 = f1 + m_b - y1 * alph1 * k11 - y2 * alph2 * k12;
0812:                        v2 = f2 + m_b - y1 * alph1 * k12 - y2 * alph2 * k22;
0813:                        double gamma = alph1 + s * alph2;
0814:                        Lobj = (gamma - s * L) + L - 0.5 * k11
0815:                                * (gamma - s * L) * (gamma - s * L) - 0.5 * k22
0816:                                * L * L - s * k12 * (gamma - s * L) * L - y1
0817:                                * (gamma - s * L) * v1 - y2 * L * v2;
0818:                        Hobj = (gamma - s * H) + H - 0.5 * k11
0819:                                * (gamma - s * H) * (gamma - s * H) - 0.5 * k22
0820:                                * H * H - s * k12 * (gamma - s * H) * H - y1
0821:                                * (gamma - s * H) * v1 - y2 * H * v2;
0822:                        if (Lobj > Hobj + m_eps) {
0823:                            a2 = L;
0824:                        } else if (Lobj < Hobj - m_eps) {
0825:                            a2 = H;
0826:                        } else {
0827:                            a2 = alph2;
0828:                        }
0829:                    }
0830:                    if (Math.abs(a2 - alph2) < m_eps * (a2 + alph2 + m_eps)) {
0831:                        return false;
0832:                    }
0833:
0834:                    // To prevent precision problems
0835:                    if (a2 > C2 - m_Del * C2) {
0836:                        a2 = C2;
0837:                    } else if (a2 <= m_Del * C2) {
0838:                        a2 = 0;
0839:                    }
0840:
0841:                    // Recompute a1
0842:                    a1 = alph1 + s * (alph2 - a2);
0843:
0844:                    // To prevent precision problems
0845:                    if (a1 > C1 - m_Del * C1) {
0846:                        a1 = C1;
0847:                    } else if (a1 <= m_Del * C1) {
0848:                        a1 = 0;
0849:                    }
0850:
0851:                    // Update sets
0852:                    if (a1 > 0) {
0853:                        m_supportVectors.insert(i1);
0854:                    } else {
0855:                        m_supportVectors.delete(i1);
0856:                    }
0857:                    if ((a1 > 0) && (a1 < C1)) {
0858:                        m_I0.insert(i1);
0859:                    } else {
0860:                        m_I0.delete(i1);
0861:                    }
0862:                    if ((y1 == 1) && (a1 == 0)) {
0863:                        m_I1.insert(i1);
0864:                    } else {
0865:                        m_I1.delete(i1);
0866:                    }
0867:                    if ((y1 == -1) && (a1 == C1)) {
0868:                        m_I2.insert(i1);
0869:                    } else {
0870:                        m_I2.delete(i1);
0871:                    }
0872:                    if ((y1 == 1) && (a1 == C1)) {
0873:                        m_I3.insert(i1);
0874:                    } else {
0875:                        m_I3.delete(i1);
0876:                    }
0877:                    if ((y1 == -1) && (a1 == 0)) {
0878:                        m_I4.insert(i1);
0879:                    } else {
0880:                        m_I4.delete(i1);
0881:                    }
0882:                    if (a2 > 0) {
0883:                        m_supportVectors.insert(i2);
0884:                    } else {
0885:                        m_supportVectors.delete(i2);
0886:                    }
0887:                    if ((a2 > 0) && (a2 < C2)) {
0888:                        m_I0.insert(i2);
0889:                    } else {
0890:                        m_I0.delete(i2);
0891:                    }
0892:                    if ((y2 == 1) && (a2 == 0)) {
0893:                        m_I1.insert(i2);
0894:                    } else {
0895:                        m_I1.delete(i2);
0896:                    }
0897:                    if ((y2 == -1) && (a2 == C2)) {
0898:                        m_I2.insert(i2);
0899:                    } else {
0900:                        m_I2.delete(i2);
0901:                    }
0902:                    if ((y2 == 1) && (a2 == C2)) {
0903:                        m_I3.insert(i2);
0904:                    } else {
0905:                        m_I3.delete(i2);
0906:                    }
0907:                    if ((y2 == -1) && (a2 == 0)) {
0908:                        m_I4.insert(i2);
0909:                    } else {
0910:                        m_I4.delete(i2);
0911:                    }
0912:
0913:                    // Update error cache using new Lagrange multipliers
0914:                    for (int j = m_I0.getNext(-1); j != -1; j = m_I0.getNext(j)) {
0915:                        if ((j != i1) && (j != i2)) {
0916:                            m_errors[j] += y1 * (a1 - alph1)
0917:                                    * m_kernel.eval(i1, j, m_data.instance(i1))
0918:                                    + y2 * (a2 - alph2)
0919:                                    * m_kernel.eval(i2, j, m_data.instance(i2));
0920:                        }
0921:                    }
0922:
0923:                    // Update error cache for i1 and i2
0924:                    m_errors[i1] += y1 * (a1 - alph1) * k11 + y2 * (a2 - alph2)
0925:                            * k12;
0926:                    m_errors[i2] += y1 * (a1 - alph1) * k12 + y2 * (a2 - alph2)
0927:                            * k22;
0928:
0929:                    // Update array with Lagrange multipliers
0930:                    m_alpha[i1] = a1;
0931:                    m_alpha[i2] = a2;
0932:
0933:                    // Update thresholds
0934:                    m_bLow = -Double.MAX_VALUE;
0935:                    m_bUp = Double.MAX_VALUE;
0936:                    m_iLow = -1;
0937:                    m_iUp = -1;
0938:                    for (int j = m_I0.getNext(-1); j != -1; j = m_I0.getNext(j)) {
0939:                        if (m_errors[j] < m_bUp) {
0940:                            m_bUp = m_errors[j];
0941:                            m_iUp = j;
0942:                        }
0943:                        if (m_errors[j] > m_bLow) {
0944:                            m_bLow = m_errors[j];
0945:                            m_iLow = j;
0946:                        }
0947:                    }
0948:                    if (!m_I0.contains(i1)) {
0949:                        if (m_I3.contains(i1) || m_I4.contains(i1)) {
0950:                            if (m_errors[i1] > m_bLow) {
0951:                                m_bLow = m_errors[i1];
0952:                                m_iLow = i1;
0953:                            }
0954:                        } else {
0955:                            if (m_errors[i1] < m_bUp) {
0956:                                m_bUp = m_errors[i1];
0957:                                m_iUp = i1;
0958:                            }
0959:                        }
0960:                    }
0961:                    if (!m_I0.contains(i2)) {
0962:                        if (m_I3.contains(i2) || m_I4.contains(i2)) {
0963:                            if (m_errors[i2] > m_bLow) {
0964:                                m_bLow = m_errors[i2];
0965:                                m_iLow = i2;
0966:                            }
0967:                        } else {
0968:                            if (m_errors[i2] < m_bUp) {
0969:                                m_bUp = m_errors[i2];
0970:                                m_iUp = i2;
0971:                            }
0972:                        }
0973:                    }
0974:                    if ((m_iLow == -1) || (m_iUp == -1)) {
0975:                        throw new Exception("This should never happen!");
0976:                    }
0977:
0978:                    // Made some progress.
0979:                    return true;
0980:                }
0981:
0982:                /**
0983:                 * Quick and dirty check whether the quadratic programming problem is solved.
0984:                 * 
0985:                 * @throws Exception if something goes wrong
0986:                 */
0987:                protected void checkClassifier() throws Exception {
0988:
0989:                    double sum = 0;
0990:                    for (int i = 0; i < m_alpha.length; i++) {
0991:                        if (m_alpha[i] > 0) {
0992:                            sum += m_class[i] * m_alpha[i];
0993:                        }
0994:                    }
0995:                    System.err.println("Sum of y(i) * alpha(i): " + sum);
0996:
0997:                    for (int i = 0; i < m_alpha.length; i++) {
0998:                        double output = SVMOutput(i, m_data.instance(i));
0999:                        if (Utils.eq(m_alpha[i], 0)) {
1000:                            if (Utils.sm(m_class[i] * output, 1)) {
1001:                                System.err.println("KKT condition 1 violated: "
1002:                                        + m_class[i] * output);
1003:                            }
1004:                        }
1005:                        if (Utils.gr(m_alpha[i], 0)
1006:                                && Utils.sm(m_alpha[i], m_C
1007:                                        * m_data.instance(i).weight())) {
1008:                            if (!Utils.eq(m_class[i] * output, 1)) {
1009:                                System.err.println("KKT condition 2 violated: "
1010:                                        + m_class[i] * output);
1011:                            }
1012:                        }
1013:                        if (Utils.eq(m_alpha[i], m_C
1014:                                * m_data.instance(i).weight())) {
1015:                            if (Utils.gr(m_class[i] * output, 1)) {
1016:                                System.err.println("KKT condition 3 violated: "
1017:                                        + m_class[i] * output);
1018:                            }
1019:                        }
1020:                    }
1021:                }
1022:            }
1023:
1024:            /** Normalize training data */
1025:            public static final int FILTER_NORMALIZE = 0;
1026:            /** Standardize training data */
1027:            public static final int FILTER_STANDARDIZE = 1;
1028:            /** No normalization/standardization */
1029:            public static final int FILTER_NONE = 2;
1030:            /** The filter to apply to the training data */
1031:            public static final Tag[] TAGS_FILTER = {
1032:                    new Tag(FILTER_NORMALIZE, "Normalize training data"),
1033:                    new Tag(FILTER_STANDARDIZE, "Standardize training data"),
1034:                    new Tag(FILTER_NONE, "No normalization/standardization"), };
1035:
1036:            /** The binary classifier(s) */
1037:            protected BinaryMISMO[][] m_classifiers = null;
1038:
1039:            /** The complexity parameter. */
1040:            protected double m_C = 1.0;
1041:
1042:            /** Epsilon for rounding. */
1043:            protected double m_eps = 1.0e-12;
1044:
1045:            /** Tolerance for accuracy of result. */
1046:            protected double m_tol = 1.0e-3;
1047:
1048:            /** Whether to normalize/standardize/neither */
1049:            protected int m_filterType = FILTER_NORMALIZE;
1050:
1051:            /** Use MIMinimax feature space?  */
1052:            protected boolean m_minimax = false;
1053:
1054:            /** The filter used to make attributes numeric. */
1055:            protected NominalToBinary m_NominalToBinary;
1056:
1057:            /** The filter used to standardize/normalize all values. */
1058:            protected Filter m_Filter = null;
1059:
1060:            /** The filter used to get rid of missing values. */
1061:            protected ReplaceMissingValues m_Missing;
1062:
1063:            /** The class index from the training data */
1064:            protected int m_classIndex = -1;
1065:
1066:            /** The class attribute */
1067:            protected Attribute m_classAttribute;
1068:
1069:            /** Kernel to use **/
1070:            protected Kernel m_kernel = new MIPolyKernel();
1071:
1072:            /** Turn off all checks and conversions? Turning them off assumes
1073:              that data is purely numeric, doesn't contain any missing values,
1074:              and has a nominal class. Turning them off also means that
1075:              no header information will be stored if the machine is linear. 
1076:              Finally, it also assumes that no instance has a weight equal to 0.*/
1077:            protected boolean m_checksTurnedOff;
1078:
1079:            /** Precision constant for updating sets */
1080:            protected static double m_Del = 1000 * Double.MIN_VALUE;
1081:
1082:            /** Whether logistic models are to be fit */
1083:            protected boolean m_fitLogisticModels = false;
1084:
1085:            /** The number of folds for the internal cross-validation */
1086:            protected int m_numFolds = -1;
1087:
1088:            /** The random number seed  */
1089:            protected int m_randomSeed = 1;
1090:
1091:            /**
1092:             * Turns off checks for missing values, etc. Use with caution.
1093:             */
1094:            public void turnChecksOff() {
1095:
1096:                m_checksTurnedOff = true;
1097:            }
1098:
1099:            /**
1100:             * Turns on checks for missing values, etc.
1101:             */
1102:            public void turnChecksOn() {
1103:
1104:                m_checksTurnedOff = false;
1105:            }
1106:
1107:            /**
1108:             * Returns default capabilities of the classifier.
1109:             *
1110:             * @return      the capabilities of this classifier
1111:             */
1112:            public Capabilities getCapabilities() {
1113:                Capabilities result = getKernel().getCapabilities();
1114:                result.setOwner(this );
1115:
1116:                // attributes
1117:                result.enable(Capability.NOMINAL_ATTRIBUTES);
1118:                result.enable(Capability.RELATIONAL_ATTRIBUTES);
1119:                result.enable(Capability.MISSING_VALUES);
1120:
1121:                // class
1122:                result.disableAllClasses();
1123:                result.disableAllClassDependencies();
1124:                result.enable(Capability.NOMINAL_CLASS);
1125:                result.enable(Capability.MISSING_CLASS_VALUES);
1126:
1127:                // other
1128:                result.enable(Capability.ONLY_MULTIINSTANCE);
1129:
1130:                return result;
1131:            }
1132:
1133:            /**
1134:             * Returns the capabilities of this multi-instance classifier for the
1135:             * relational data.
1136:             *
1137:             * @return            the capabilities of this object
1138:             * @see               Capabilities
1139:             */
1140:            public Capabilities getMultiInstanceCapabilities() {
1141:                Capabilities result = ((MultiInstanceCapabilitiesHandler) getKernel())
1142:                        .getMultiInstanceCapabilities();
1143:                result.setOwner(this );
1144:
1145:                // attribute
1146:                result.enableAllAttributeDependencies();
1147:                // with NominalToBinary we can also handle nominal attributes, but only
1148:                // if the kernel can handle numeric attributes
1149:                if (result.handles(Capability.NUMERIC_ATTRIBUTES))
1150:                    result.enable(Capability.NOMINAL_ATTRIBUTES);
1151:                result.enable(Capability.MISSING_VALUES);
1152:
1153:                return result;
1154:            }
1155:
1156:            /**
1157:             * Method for building the classifier. Implements a one-against-one
1158:             * wrapper for multi-class problems.
1159:             *
1160:             * @param insts the set of training instances
1161:             * @throws Exception if the classifier can't be built successfully
1162:             */
1163:            public void buildClassifier(Instances insts) throws Exception {
1164:                if (!m_checksTurnedOff) {
1165:                    // can classifier handle the data?
1166:                    getCapabilities().testWithFail(insts);
1167:
1168:                    // remove instances with missing class
1169:                    insts = new Instances(insts);
1170:                    insts.deleteWithMissingClass();
1171:
1172:                    /* Removes all the instances with weight equal to 0.
1173:                       MUST be done since condition (8) of Keerthi's paper 
1174:                       is made with the assertion Ci > 0 (See equation (3a). */
1175:                    Instances data = new Instances(insts, insts.numInstances());
1176:                    for (int i = 0; i < insts.numInstances(); i++) {
1177:                        if (insts.instance(i).weight() > 0)
1178:                            data.add(insts.instance(i));
1179:                    }
1180:                    if (data.numInstances() == 0) {
1181:                        throw new Exception(
1182:                                "No training instances left after removing "
1183:                                        + "instance with either a weight null or a missing class!");
1184:                    }
1185:                    insts = data;
1186:                }
1187:
1188:                // filter data
1189:                if (!m_checksTurnedOff)
1190:                    m_Missing = new ReplaceMissingValues();
1191:                else
1192:                    m_Missing = null;
1193:
1194:                if (getCapabilities().handles(Capability.NUMERIC_ATTRIBUTES)) {
1195:                    boolean onlyNumeric = true;
1196:                    if (!m_checksTurnedOff) {
1197:                        for (int i = 0; i < insts.numAttributes(); i++) {
1198:                            if (i != insts.classIndex()) {
1199:                                if (!insts.attribute(i).isNumeric()) {
1200:                                    onlyNumeric = false;
1201:                                    break;
1202:                                }
1203:                            }
1204:                        }
1205:                    }
1206:
1207:                    if (!onlyNumeric) {
1208:                        m_NominalToBinary = new NominalToBinary();
1209:                        // exclude the bag attribute
1210:                        m_NominalToBinary.setAttributeIndices("2-last");
1211:                    } else {
1212:                        m_NominalToBinary = null;
1213:                    }
1214:                } else {
1215:                    m_NominalToBinary = null;
1216:                }
1217:
1218:                if (m_filterType == FILTER_STANDARDIZE)
1219:                    m_Filter = new Standardize();
1220:                else if (m_filterType == FILTER_NORMALIZE)
1221:                    m_Filter = new Normalize();
1222:                else
1223:                    m_Filter = null;
1224:
1225:                Instances transformedInsts;
1226:                Filter convertToProp = new MultiInstanceToPropositional();
1227:                Filter convertToMI = new PropositionalToMultiInstance();
1228:
1229:                //transform the data into single-instance format
1230:                if (m_minimax) {
1231:                    /* using SimpleMI class minimax transform method. 
1232:                       this method transforms the multi-instance dataset into minmax feature space (single-instance) */
1233:                    SimpleMI transMinimax = new SimpleMI();
1234:                    transMinimax.setTransformMethod(new SelectedTag(
1235:                            SimpleMI.TRANSFORMMETHOD_MINIMAX,
1236:                            SimpleMI.TAGS_TRANSFORMMETHOD));
1237:                    transformedInsts = transMinimax.transform(insts);
1238:                } else {
1239:                    convertToProp.setInputFormat(insts);
1240:                    transformedInsts = Filter.useFilter(insts, convertToProp);
1241:                }
1242:
1243:                if (m_Missing != null) {
1244:                    m_Missing.setInputFormat(transformedInsts);
1245:                    transformedInsts = Filter.useFilter(transformedInsts,
1246:                            m_Missing);
1247:                }
1248:
1249:                if (m_NominalToBinary != null) {
1250:                    m_NominalToBinary.setInputFormat(transformedInsts);
1251:                    transformedInsts = Filter.useFilter(transformedInsts,
1252:                            m_NominalToBinary);
1253:                }
1254:
1255:                if (m_Filter != null) {
1256:                    m_Filter.setInputFormat(transformedInsts);
1257:                    transformedInsts = Filter.useFilter(transformedInsts,
1258:                            m_Filter);
1259:                }
1260:
1261:                // convert the single-instance format to multi-instance format
1262:                convertToMI.setInputFormat(transformedInsts);
1263:                insts = Filter.useFilter(transformedInsts, convertToMI);
1264:
1265:                m_classIndex = insts.classIndex();
1266:                m_classAttribute = insts.classAttribute();
1267:
1268:                // Generate subsets representing each class
1269:                Instances[] subsets = new Instances[insts.numClasses()];
1270:                for (int i = 0; i < insts.numClasses(); i++) {
1271:                    subsets[i] = new Instances(insts, insts.numInstances());
1272:                }
1273:                for (int j = 0; j < insts.numInstances(); j++) {
1274:                    Instance inst = insts.instance(j);
1275:                    subsets[(int) inst.classValue()].add(inst);
1276:                }
1277:                for (int i = 0; i < insts.numClasses(); i++) {
1278:                    subsets[i].compactify();
1279:                }
1280:
1281:                // Build the binary classifiers
1282:                Random rand = new Random(m_randomSeed);
1283:                m_classifiers = new BinaryMISMO[insts.numClasses()][insts
1284:                        .numClasses()];
1285:                for (int i = 0; i < insts.numClasses(); i++) {
1286:                    for (int j = i + 1; j < insts.numClasses(); j++) {
1287:                        m_classifiers[i][j] = new BinaryMISMO();
1288:                        m_classifiers[i][j].setKernel(Kernel
1289:                                .makeCopy(getKernel()));
1290:                        Instances data = new Instances(insts, insts
1291:                                .numInstances());
1292:                        for (int k = 0; k < subsets[i].numInstances(); k++) {
1293:                            data.add(subsets[i].instance(k));
1294:                        }
1295:                        for (int k = 0; k < subsets[j].numInstances(); k++) {
1296:                            data.add(subsets[j].instance(k));
1297:                        }
1298:                        data.compactify();
1299:                        data.randomize(rand);
1300:                        m_classifiers[i][j].buildClassifier(data, i, j,
1301:                                m_fitLogisticModels, m_numFolds, m_randomSeed);
1302:                    }
1303:                }
1304:
1305:            }
1306:
1307:            /**
1308:             * Estimates class probabilities for given instance.
1309:             * 
1310:             * @param inst the instance to compute the distribution for
1311:             * @return the class probabilities
1312:             * @throws Exception if computation fails
1313:             */
1314:            public double[] distributionForInstance(Instance inst)
1315:                    throws Exception {
1316:
1317:                //convert instance into instances
1318:                Instances insts = new Instances(inst.dataset(), 0);
1319:                insts.add(inst);
1320:
1321:                //transform the data into single-instance format
1322:                Filter convertToProp = new MultiInstanceToPropositional();
1323:                Filter convertToMI = new PropositionalToMultiInstance();
1324:
1325:                if (m_minimax) { // using minimax feature space
1326:                    SimpleMI transMinimax = new SimpleMI();
1327:                    transMinimax.setTransformMethod(new SelectedTag(
1328:                            SimpleMI.TRANSFORMMETHOD_MINIMAX,
1329:                            SimpleMI.TAGS_TRANSFORMMETHOD));
1330:                    insts = transMinimax.transform(insts);
1331:                } else {
1332:                    convertToProp.setInputFormat(insts);
1333:                    insts = Filter.useFilter(insts, convertToProp);
1334:                }
1335:
1336:                // Filter instances 
1337:                if (m_Missing != null)
1338:                    insts = Filter.useFilter(insts, m_Missing);
1339:
1340:                if (m_Filter != null)
1341:                    insts = Filter.useFilter(insts, m_Filter);
1342:
1343:                // convert the single-instance format to multi-instance format
1344:                convertToMI.setInputFormat(insts);
1345:                insts = Filter.useFilter(insts, convertToMI);
1346:
1347:                inst = insts.instance(0);
1348:
1349:                if (!m_fitLogisticModels) {
1350:                    double[] result = new double[inst.numClasses()];
1351:                    for (int i = 0; i < inst.numClasses(); i++) {
1352:                        for (int j = i + 1; j < inst.numClasses(); j++) {
1353:                            if ((m_classifiers[i][j].m_alpha != null)
1354:                                    || (m_classifiers[i][j].m_sparseWeights != null)) {
1355:                                double output = m_classifiers[i][j].SVMOutput(
1356:                                        -1, inst);
1357:                                if (output > 0) {
1358:                                    result[j] += 1;
1359:                                } else {
1360:                                    result[i] += 1;
1361:                                }
1362:                            }
1363:                        }
1364:                    }
1365:                    Utils.normalize(result);
1366:                    return result;
1367:                } else {
1368:
1369:                    // We only need to do pairwise coupling if there are more
1370:                    // then two classes.
1371:                    if (inst.numClasses() == 2) {
1372:                        double[] newInst = new double[2];
1373:                        newInst[0] = m_classifiers[0][1].SVMOutput(-1, inst);
1374:                        newInst[1] = Instance.missingValue();
1375:                        return m_classifiers[0][1].m_logistic
1376:                                .distributionForInstance(new Instance(1,
1377:                                        newInst));
1378:                    }
1379:                    double[][] r = new double[inst.numClasses()][inst
1380:                            .numClasses()];
1381:                    double[][] n = new double[inst.numClasses()][inst
1382:                            .numClasses()];
1383:                    for (int i = 0; i < inst.numClasses(); i++) {
1384:                        for (int j = i + 1; j < inst.numClasses(); j++) {
1385:                            if ((m_classifiers[i][j].m_alpha != null)
1386:                                    || (m_classifiers[i][j].m_sparseWeights != null)) {
1387:                                double[] newInst = new double[2];
1388:                                newInst[0] = m_classifiers[i][j].SVMOutput(-1,
1389:                                        inst);
1390:                                newInst[1] = Instance.missingValue();
1391:                                r[i][j] = m_classifiers[i][j].m_logistic
1392:                                        .distributionForInstance(new Instance(
1393:                                                1, newInst))[0];
1394:                                n[i][j] = m_classifiers[i][j].m_sumOfWeights;
1395:                            }
1396:                        }
1397:                    }
1398:                    return pairwiseCoupling(n, r);
1399:                }
1400:            }
1401:
1402:            /**
1403:             * Implements pairwise coupling.
1404:             *
1405:             * @param n the sum of weights used to train each model
1406:             * @param r the probability estimate from each model
1407:             * @return the coupled estimates
1408:             */
1409:            public double[] pairwiseCoupling(double[][] n, double[][] r) {
1410:
1411:                // Initialize p and u array
1412:                double[] p = new double[r.length];
1413:                for (int i = 0; i < p.length; i++) {
1414:                    p[i] = 1.0 / (double) p.length;
1415:                }
1416:                double[][] u = new double[r.length][r.length];
1417:                for (int i = 0; i < r.length; i++) {
1418:                    for (int j = i + 1; j < r.length; j++) {
1419:                        u[i][j] = 0.5;
1420:                    }
1421:                }
1422:
1423:                // firstSum doesn't change
1424:                double[] firstSum = new double[p.length];
1425:                for (int i = 0; i < p.length; i++) {
1426:                    for (int j = i + 1; j < p.length; j++) {
1427:                        firstSum[i] += n[i][j] * r[i][j];
1428:                        firstSum[j] += n[i][j] * (1 - r[i][j]);
1429:                    }
1430:                }
1431:
1432:                // Iterate until convergence
1433:                boolean changed;
1434:                do {
1435:                    changed = false;
1436:                    double[] secondSum = new double[p.length];
1437:                    for (int i = 0; i < p.length; i++) {
1438:                        for (int j = i + 1; j < p.length; j++) {
1439:                            secondSum[i] += n[i][j] * u[i][j];
1440:                            secondSum[j] += n[i][j] * (1 - u[i][j]);
1441:                        }
1442:                    }
1443:                    for (int i = 0; i < p.length; i++) {
1444:                        if ((firstSum[i] == 0) || (secondSum[i] == 0)) {
1445:                            if (p[i] > 0) {
1446:                                changed = true;
1447:                            }
1448:                            p[i] = 0;
1449:                        } else {
1450:                            double factor = firstSum[i] / secondSum[i];
1451:                            double pOld = p[i];
1452:                            p[i] *= factor;
1453:                            if (Math.abs(pOld - p[i]) > 1.0e-3) {
1454:                                changed = true;
1455:                            }
1456:                        }
1457:                    }
1458:                    Utils.normalize(p);
1459:                    for (int i = 0; i < r.length; i++) {
1460:                        for (int j = i + 1; j < r.length; j++) {
1461:                            u[i][j] = p[i] / (p[i] + p[j]);
1462:                        }
1463:                    }
1464:                } while (changed);
1465:                return p;
1466:            }
1467:
1468:            /**
1469:             * Returns the weights in sparse format.
1470:             * 
1471:             * @return the weights in sparse format
1472:             */
1473:            public double[][][] sparseWeights() {
1474:
1475:                int numValues = m_classAttribute.numValues();
1476:                double[][][] sparseWeights = new double[numValues][numValues][];
1477:
1478:                for (int i = 0; i < numValues; i++) {
1479:                    for (int j = i + 1; j < numValues; j++) {
1480:                        sparseWeights[i][j] = m_classifiers[i][j].m_sparseWeights;
1481:                    }
1482:                }
1483:
1484:                return sparseWeights;
1485:            }
1486:
1487:            /**
1488:             * Returns the indices in sparse format.
1489:             * 
1490:             * @return the indices in sparse format
1491:             */
1492:            public int[][][] sparseIndices() {
1493:
1494:                int numValues = m_classAttribute.numValues();
1495:                int[][][] sparseIndices = new int[numValues][numValues][];
1496:
1497:                for (int i = 0; i < numValues; i++) {
1498:                    for (int j = i + 1; j < numValues; j++) {
1499:                        sparseIndices[i][j] = m_classifiers[i][j].m_sparseIndices;
1500:                    }
1501:                }
1502:
1503:                return sparseIndices;
1504:            }
1505:
1506:            /**
1507:             * Returns the bias of each binary SMO.
1508:             * 
1509:             * @return the bias of each binary SMO
1510:             */
1511:            public double[][] bias() {
1512:
1513:                int numValues = m_classAttribute.numValues();
1514:                double[][] bias = new double[numValues][numValues];
1515:
1516:                for (int i = 0; i < numValues; i++) {
1517:                    for (int j = i + 1; j < numValues; j++) {
1518:                        bias[i][j] = m_classifiers[i][j].m_b;
1519:                    }
1520:                }
1521:
1522:                return bias;
1523:            }
1524:
1525:            /**
1526:             * Returns the number of values of the class attribute.
1527:             * 
1528:             * @return the number values of the class attribute
1529:             */
1530:            public int numClassAttributeValues() {
1531:
1532:                return m_classAttribute.numValues();
1533:            }
1534:
1535:            /**
1536:             * Returns the names of the class attributes.
1537:             * 
1538:             * @return the names of the class attributes
1539:             */
1540:            public String[] classAttributeNames() {
1541:
1542:                int numValues = m_classAttribute.numValues();
1543:
1544:                String[] classAttributeNames = new String[numValues];
1545:
1546:                for (int i = 0; i < numValues; i++) {
1547:                    classAttributeNames[i] = m_classAttribute.value(i);
1548:                }
1549:
1550:                return classAttributeNames;
1551:            }
1552:
1553:            /**
1554:             * Returns the attribute names.
1555:             * 
1556:             * @return the attribute names
1557:             */
1558:            public String[][][] attributeNames() {
1559:
1560:                int numValues = m_classAttribute.numValues();
1561:                String[][][] attributeNames = new String[numValues][numValues][];
1562:
1563:                for (int i = 0; i < numValues; i++) {
1564:                    for (int j = i + 1; j < numValues; j++) {
1565:                        int numAttributes = m_classifiers[i][j].m_data
1566:                                .numAttributes();
1567:                        String[] attrNames = new String[numAttributes];
1568:                        for (int k = 0; k < numAttributes; k++) {
1569:                            attrNames[k] = m_classifiers[i][j].m_data
1570:                                    .attribute(k).name();
1571:                        }
1572:                        attributeNames[i][j] = attrNames;
1573:                    }
1574:                }
1575:                return attributeNames;
1576:            }
1577:
1578:            /**
1579:             * Returns an enumeration describing the available options.
1580:             *
1581:             * @return an enumeration of all the available options.
1582:             */
1583:            public Enumeration listOptions() {
1584:
1585:                Vector result = new Vector();
1586:
1587:                Enumeration enm = super .listOptions();
1588:                while (enm.hasMoreElements())
1589:                    result.addElement(enm.nextElement());
1590:
1591:                result
1592:                        .addElement(new Option(
1593:                                "\tTurns off all checks - use with caution!\n"
1594:                                        + "\tTurning them off assumes that data is purely numeric, doesn't\n"
1595:                                        + "\tcontain any missing values, and has a nominal class. Turning them\n"
1596:                                        + "\toff also means that no header information will be stored if the\n"
1597:                                        + "\tmachine is linear. Finally, it also assumes that no instance has\n"
1598:                                        + "\ta weight equal to 0.\n"
1599:                                        + "\t(default: checks on)",
1600:                                "no-checks", 0, "-no-checks"));
1601:
1602:                result.addElement(new Option(
1603:                        "\tThe complexity constant C. (default 1)", "C", 1,
1604:                        "-C <double>"));
1605:
1606:                result.addElement(new Option(
1607:                        "\tWhether to 0=normalize/1=standardize/2=neither.\n"
1608:                                + "\t(default 0=normalize)", "N", 1, "-N"));
1609:
1610:                result.addElement(new Option("\tUse MIminimax feature space. ",
1611:                        "I", 0, "-I"));
1612:
1613:                result.addElement(new Option(
1614:                        "\tThe tolerance parameter. (default 1.0e-3)", "L", 1,
1615:                        "-L <double>"));
1616:
1617:                result.addElement(new Option(
1618:                        "\tThe epsilon for round-off error. (default 1.0e-12)",
1619:                        "P", 1, "-P <double>"));
1620:
1621:                result
1622:                        .addElement(new Option(
1623:                                "\tFit logistic models to SVM outputs. ", "M",
1624:                                0, "-M"));
1625:
1626:                result.addElement(new Option(
1627:                        "\tThe number of folds for the internal cross-validation. \n"
1628:                                + "\t(default -1, use training data)", "V", 1,
1629:                        "-V <double>"));
1630:
1631:                result.addElement(new Option(
1632:                        "\tThe random number seed. (default 1)", "W", 1,
1633:                        "-W <double>"));
1634:
1635:                result
1636:                        .addElement(new Option(
1637:                                "\tThe Kernel to use.\n"
1638:                                        + "\t(default: weka.classifiers.functions.supportVector.PolyKernel)",
1639:                                "K", 1, "-K <classname and parameters>"));
1640:
1641:                result.addElement(new Option("", "", 0,
1642:                        "\nOptions specific to kernel "
1643:                                + getKernel().getClass().getName() + ":"));
1644:
1645:                enm = ((OptionHandler) getKernel()).listOptions();
1646:                while (enm.hasMoreElements())
1647:                    result.addElement(enm.nextElement());
1648:
1649:                return result.elements();
1650:            }
1651:
1652:            /**
1653:             * Parses a given list of options. <p/>
1654:             * 
1655:             <!-- options-start -->
1656:             * Valid options are: <p/>
1657:             * 
1658:             * <pre> -D
1659:             *  If set, classifier is run in debug mode and
1660:             *  may output additional info to the console</pre>
1661:             * 
1662:             * <pre> -no-checks
1663:             *  Turns off all checks - use with caution!
1664:             *  Turning them off assumes that data is purely numeric, doesn't
1665:             *  contain any missing values, and has a nominal class. Turning them
1666:             *  off also means that no header information will be stored if the
1667:             *  machine is linear. Finally, it also assumes that no instance has
1668:             *  a weight equal to 0.
1669:             *  (default: checks on)</pre>
1670:             * 
1671:             * <pre> -C &lt;double&gt;
1672:             *  The complexity constant C. (default 1)</pre>
1673:             * 
1674:             * <pre> -N
1675:             *  Whether to 0=normalize/1=standardize/2=neither.
1676:             *  (default 0=normalize)</pre>
1677:             * 
1678:             * <pre> -I
1679:             *  Use MIminimax feature space. </pre>
1680:             * 
1681:             * <pre> -L &lt;double&gt;
1682:             *  The tolerance parameter. (default 1.0e-3)</pre>
1683:             * 
1684:             * <pre> -P &lt;double&gt;
1685:             *  The epsilon for round-off error. (default 1.0e-12)</pre>
1686:             * 
1687:             * <pre> -M
1688:             *  Fit logistic models to SVM outputs. </pre>
1689:             * 
1690:             * <pre> -V &lt;double&gt;
1691:             *  The number of folds for the internal cross-validation. 
1692:             *  (default -1, use training data)</pre>
1693:             * 
1694:             * <pre> -W &lt;double&gt;
1695:             *  The random number seed. (default 1)</pre>
1696:             * 
1697:             * <pre> -K &lt;classname and parameters&gt;
1698:             *  The Kernel to use.
1699:             *  (default: weka.classifiers.functions.supportVector.PolyKernel)</pre>
1700:             * 
1701:             * <pre> 
1702:             * Options specific to kernel weka.classifiers.mi.supportVector.MIPolyKernel:
1703:             * </pre>
1704:             * 
1705:             * <pre> -D
1706:             *  Enables debugging output (if available) to be printed.
1707:             *  (default: off)</pre>
1708:             * 
1709:             * <pre> -no-checks
1710:             *  Turns off all checks - use with caution!
1711:             *  (default: checks on)</pre>
1712:             * 
1713:             * <pre> -C &lt;num&gt;
1714:             *  The size of the cache (a prime number).
1715:             *  (default: 250007)</pre>
1716:             * 
1717:             * <pre> -E &lt;num&gt;
1718:             *  The Exponent to use.
1719:             *  (default: 1.0)</pre>
1720:             * 
1721:             * <pre> -L
1722:             *  Use lower-order terms.
1723:             *  (default: no)</pre>
1724:             * 
1725:             <!-- options-end -->
1726:             *
1727:             * @param options the list of options as an array of strings
1728:             * @throws Exception if an option is not supported 
1729:             */
1730:            public void setOptions(String[] options) throws Exception {
1731:                String tmpStr;
1732:                String[] tmpOptions;
1733:
1734:                setChecksTurnedOff(Utils.getFlag("no-checks", options));
1735:
1736:                tmpStr = Utils.getOption('C', options);
1737:                if (tmpStr.length() != 0)
1738:                    setC(Double.parseDouble(tmpStr));
1739:                else
1740:                    setC(1.0);
1741:
1742:                tmpStr = Utils.getOption('L', options);
1743:                if (tmpStr.length() != 0)
1744:                    setToleranceParameter(Double.parseDouble(tmpStr));
1745:                else
1746:                    setToleranceParameter(1.0e-3);
1747:
1748:                tmpStr = Utils.getOption('P', options);
1749:                if (tmpStr.length() != 0)
1750:                    setEpsilon(new Double(tmpStr));
1751:                else
1752:                    setEpsilon(1.0e-12);
1753:
1754:                setMinimax(Utils.getFlag('I', options));
1755:
1756:                tmpStr = Utils.getOption('N', options);
1757:                if (tmpStr.length() != 0)
1758:                    setFilterType(new SelectedTag(Integer.parseInt(tmpStr),
1759:                            TAGS_FILTER));
1760:                else
1761:                    setFilterType(new SelectedTag(FILTER_NORMALIZE, TAGS_FILTER));
1762:
1763:                setBuildLogisticModels(Utils.getFlag('M', options));
1764:
1765:                tmpStr = Utils.getOption('V', options);
1766:                if (tmpStr.length() != 0)
1767:                    m_numFolds = Integer.parseInt(tmpStr);
1768:                else
1769:                    m_numFolds = -1;
1770:
1771:                tmpStr = Utils.getOption('W', options);
1772:                if (tmpStr.length() != 0)
1773:                    setRandomSeed(Integer.parseInt(tmpStr));
1774:                else
1775:                    setRandomSeed(1);
1776:
1777:                tmpStr = Utils.getOption('K', options);
1778:                tmpOptions = Utils.splitOptions(tmpStr);
1779:                if (tmpOptions.length != 0) {
1780:                    tmpStr = tmpOptions[0];
1781:                    tmpOptions[0] = "";
1782:                    setKernel(Kernel.forName(tmpStr, tmpOptions));
1783:                }
1784:
1785:                super .setOptions(options);
1786:            }
1787:
1788:            /**
1789:             * Gets the current settings of the classifier.
1790:             *
1791:             * @return an array of strings suitable for passing to setOptions
1792:             */
1793:            public String[] getOptions() {
1794:                int i;
1795:                Vector result;
1796:                String[] options;
1797:
1798:                result = new Vector();
1799:                options = super .getOptions();
1800:                for (i = 0; i < options.length; i++)
1801:                    result.add(options[i]);
1802:
1803:                if (getChecksTurnedOff())
1804:                    result.add("-no-checks");
1805:
1806:                result.add("-C");
1807:                result.add("" + getC());
1808:
1809:                result.add("-L");
1810:                result.add("" + getToleranceParameter());
1811:
1812:                result.add("-P");
1813:                result.add("" + getEpsilon());
1814:
1815:                result.add("-N");
1816:                result.add("" + m_filterType);
1817:
1818:                if (getMinimax())
1819:                    result.add("-I");
1820:
1821:                if (getBuildLogisticModels())
1822:                    result.add("-M");
1823:
1824:                result.add("-V");
1825:                result.add("" + getNumFolds());
1826:
1827:                result.add("-W");
1828:                result.add("" + getRandomSeed());
1829:
1830:                result.add("-K");
1831:                result.add("" + getKernel().getClass().getName() + " "
1832:                        + Utils.joinOptions(getKernel().getOptions()));
1833:
1834:                return (String[]) result.toArray(new String[result.size()]);
1835:            }
1836:
1837:            /**
1838:             * Disables or enables the checks (which could be time-consuming). Use with
1839:             * caution!
1840:             * 
1841:             * @param value	if true turns off all checks
1842:             */
1843:            public void setChecksTurnedOff(boolean value) {
1844:                if (value)
1845:                    turnChecksOff();
1846:                else
1847:                    turnChecksOn();
1848:            }
1849:
1850:            /**
1851:             * Returns whether the checks are turned off or not.
1852:             * 
1853:             * @return		true if the checks are turned off
1854:             */
1855:            public boolean getChecksTurnedOff() {
1856:                return m_checksTurnedOff;
1857:            }
1858:
1859:            /**
1860:             * Returns the tip text for this property
1861:             * 
1862:             * @return 		tip text for this property suitable for
1863:             * 			displaying in the explorer/experimenter gui
1864:             */
1865:            public String checksTurnedOffTipText() {
1866:                return "Turns time-consuming checks off - use with caution.";
1867:            }
1868:
1869:            /**
1870:             * Returns the tip text for this property
1871:             * 
1872:             * @return 		tip text for this property suitable for
1873:             * 			displaying in the explorer/experimenter gui
1874:             */
1875:            public String kernelTipText() {
1876:                return "The kernel to use.";
1877:            }
1878:
1879:            /**
1880:             * Gets the kernel to use.
1881:             *
1882:             * @return 		the kernel
1883:             */
1884:            public Kernel getKernel() {
1885:                return m_kernel;
1886:            }
1887:
1888:            /**
1889:             * Sets the kernel to use.
1890:             *
1891:             * @param value	the kernel
1892:             */
1893:            public void setKernel(Kernel value) {
1894:                if (!(value instanceof  MultiInstanceCapabilitiesHandler))
1895:                    throw new IllegalArgumentException(
1896:                            "Kernel must be able to handle multi-instance data!\n"
1897:                                    + "(This one does not implement "
1898:                                    + MultiInstanceCapabilitiesHandler.class
1899:                                            .getName() + ")");
1900:
1901:                m_kernel = value;
1902:            }
1903:
1904:            /**
1905:             * Returns the tip text for this property
1906:             * @return tip text for this property suitable for
1907:             * displaying in the explorer/experimenter gui
1908:             */
1909:            public String cTipText() {
1910:                return "The complexity parameter C.";
1911:            }
1912:
1913:            /**
1914:             * Get the value of C.
1915:             *
1916:             * @return Value of C.
1917:             */
1918:            public double getC() {
1919:
1920:                return m_C;
1921:            }
1922:
1923:            /**
1924:             * Set the value of C.
1925:             *
1926:             * @param v  Value to assign to C.
1927:             */
1928:            public void setC(double v) {
1929:
1930:                m_C = v;
1931:            }
1932:
1933:            /**
1934:             * Returns the tip text for this property
1935:             * @return tip text for this property suitable for
1936:             * displaying in the explorer/experimenter gui
1937:             */
1938:            public String toleranceParameterTipText() {
1939:                return "The tolerance parameter (shouldn't be changed).";
1940:            }
1941:
1942:            /**
1943:             * Get the value of tolerance parameter.
1944:             * @return Value of tolerance parameter.
1945:             */
1946:            public double getToleranceParameter() {
1947:
1948:                return m_tol;
1949:            }
1950:
1951:            /**
1952:             * Set the value of tolerance parameter.
1953:             * @param v  Value to assign to tolerance parameter.
1954:             */
1955:            public void setToleranceParameter(double v) {
1956:
1957:                m_tol = v;
1958:            }
1959:
1960:            /**
1961:             * Returns the tip text for this property
1962:             * @return tip text for this property suitable for
1963:             * displaying in the explorer/experimenter gui
1964:             */
1965:            public String epsilonTipText() {
1966:                return "The epsilon for round-off error (shouldn't be changed).";
1967:            }
1968:
1969:            /**
1970:             * Get the value of epsilon.
1971:             * @return Value of epsilon.
1972:             */
1973:            public double getEpsilon() {
1974:
1975:                return m_eps;
1976:            }
1977:
1978:            /**
1979:             * Set the value of epsilon.
1980:             * @param v  Value to assign to epsilon.
1981:             */
1982:            public void setEpsilon(double v) {
1983:
1984:                m_eps = v;
1985:            }
1986:
1987:            /**
1988:             * Returns the tip text for this property
1989:             * @return tip text for this property suitable for
1990:             * displaying in the explorer/experimenter gui
1991:             */
1992:            public String filterTypeTipText() {
1993:                return "Determines how/if the data will be transformed.";
1994:            }
1995:
1996:            /**
1997:             * Gets how the training data will be transformed. Will be one of
1998:             * FILTER_NORMALIZE, FILTER_STANDARDIZE, FILTER_NONE.
1999:             *
2000:             * @return the filtering mode
2001:             */
2002:            public SelectedTag getFilterType() {
2003:
2004:                return new SelectedTag(m_filterType, TAGS_FILTER);
2005:            }
2006:
2007:            /**
2008:             * Sets how the training data will be transformed. Should be one of
2009:             * FILTER_NORMALIZE, FILTER_STANDARDIZE, FILTER_NONE.
2010:             *
2011:             * @param newType the new filtering mode
2012:             */
2013:            public void setFilterType(SelectedTag newType) {
2014:
2015:                if (newType.getTags() == TAGS_FILTER) {
2016:                    m_filterType = newType.getSelectedTag().getID();
2017:                }
2018:            }
2019:
2020:            /**
2021:             * Returns the tip text for this property
2022:             *
2023:             * @return tip text for this property suitable for
2024:             * displaying in the explorer/experimenter gui
2025:             */
2026:            public String minimaxTipText() {
2027:                return "Whether the MIMinimax feature space is to be used.";
2028:            }
2029:
2030:            /**
2031:             * Check if the MIMinimax feature space is to be used.
2032:             * @return true if minimax
2033:             */
2034:            public boolean getMinimax() {
2035:
2036:                return m_minimax;
2037:            }
2038:
2039:            /**
2040:             * Set if the MIMinimax feature space is to be used.
2041:             * @param v  true if RBF
2042:             */
2043:            public void setMinimax(boolean v) {
2044:                m_minimax = v;
2045:            }
2046:
2047:            /**
2048:             * Returns the tip text for this property
2049:             * @return tip text for this property suitable for
2050:             * displaying in the explorer/experimenter gui
2051:             */
2052:            public String buildLogisticModelsTipText() {
2053:                return "Whether to fit logistic models to the outputs (for proper "
2054:                        + "probability estimates).";
2055:            }
2056:
2057:            /**
2058:             * Get the value of buildLogisticModels.
2059:             *
2060:             * @return Value of buildLogisticModels.
2061:             */
2062:            public boolean getBuildLogisticModels() {
2063:
2064:                return m_fitLogisticModels;
2065:            }
2066:
2067:            /**
2068:             * Set the value of buildLogisticModels.
2069:             *
2070:             * @param newbuildLogisticModels Value to assign to buildLogisticModels.
2071:             */
2072:            public void setBuildLogisticModels(boolean newbuildLogisticModels) {
2073:
2074:                m_fitLogisticModels = newbuildLogisticModels;
2075:            }
2076:
2077:            /**
2078:             * Returns the tip text for this property
2079:             * @return tip text for this property suitable for
2080:             * displaying in the explorer/experimenter gui
2081:             */
2082:            public String numFoldsTipText() {
2083:                return "The number of folds for cross-validation used to generate "
2084:                        + "training data for logistic models (-1 means use training data).";
2085:            }
2086:
2087:            /**
2088:             * Get the value of numFolds.
2089:             *
2090:             * @return Value of numFolds.
2091:             */
2092:            public int getNumFolds() {
2093:
2094:                return m_numFolds;
2095:            }
2096:
2097:            /**
2098:             * Set the value of numFolds.
2099:             *
2100:             * @param newnumFolds Value to assign to numFolds.
2101:             */
2102:            public void setNumFolds(int newnumFolds) {
2103:
2104:                m_numFolds = newnumFolds;
2105:            }
2106:
2107:            /**
2108:             * Returns the tip text for this property
2109:             * @return tip text for this property suitable for
2110:             * displaying in the explorer/experimenter gui
2111:             */
2112:            public String randomSeedTipText() {
2113:                return "Random number seed for the cross-validation.";
2114:            }
2115:
2116:            /**
2117:             * Get the value of randomSeed.
2118:             *
2119:             * @return Value of randomSeed.
2120:             */
2121:            public int getRandomSeed() {
2122:
2123:                return m_randomSeed;
2124:            }
2125:
2126:            /**
2127:             * Set the value of randomSeed.
2128:             *
2129:             * @param newrandomSeed Value to assign to randomSeed.
2130:             */
2131:            public void setRandomSeed(int newrandomSeed) {
2132:
2133:                m_randomSeed = newrandomSeed;
2134:            }
2135:
2136:            /**
2137:             * Prints out the classifier.
2138:             *
2139:             * @return a description of the classifier as a string
2140:             */
2141:            public String toString() {
2142:
2143:                StringBuffer text = new StringBuffer();
2144:
2145:                if ((m_classAttribute == null)) {
2146:                    return "SMO: No model built yet.";
2147:                }
2148:                try {
2149:                    text.append("SMO\n\n");
2150:                    for (int i = 0; i < m_classAttribute.numValues(); i++) {
2151:                        for (int j = i + 1; j < m_classAttribute.numValues(); j++) {
2152:                            text.append("Classifier for classes: "
2153:                                    + m_classAttribute.value(i) + ", "
2154:                                    + m_classAttribute.value(j) + "\n\n");
2155:                            text.append(m_classifiers[i][j]);
2156:                            if (m_fitLogisticModels) {
2157:                                text.append("\n\n");
2158:                                if (m_classifiers[i][j].m_logistic == null) {
2159:                                    text
2160:                                            .append("No logistic model has been fit.\n");
2161:                                } else {
2162:                                    text.append(m_classifiers[i][j].m_logistic);
2163:                                }
2164:                            }
2165:                            text.append("\n\n");
2166:                        }
2167:                    }
2168:                } catch (Exception e) {
2169:                    return "Can't print SMO classifier.";
2170:                }
2171:
2172:                return text.toString();
2173:            }
2174:
2175:            /**
2176:             * Main method for testing this class.
2177:             * 
2178:             * @param argv the commandline parameters
2179:             */
2180:            public static void main(String[] argv) {
2181:                runClassifier(new MISMO(), argv);
2182:            }
2183:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.