source: orange/orange/OrangeWidgets/Evaluate/OWTestLearners.py @ 9528:9aa244e3b654

Revision 9528:9aa244e3b654, 25.4 KB checked in by ales_erjavec <ales.erjavec@…>, 2 years ago (diff)

No longer stores signal ids in the learner instances (the ids makes the output unpicklable and can break the widget if the same learner is used in multiple TestLearner widgets).
Fixed recomputeCM ('self.learners.values()' and 'self.result.learners' order mismatch).

Line 
1"""
2<name>Test Learners</name>
3<description>Estimates the predictive performance of learners on a data set.</description>
4<icon>icons/TestLearners.png</icon>
5<contact>Blaz Zupan (blaz.zupan(@at@)fri.uni-lj.si)</contact>
6<priority>200</priority>
7"""
8#
9# OWTestLearners.py
10#
11from OWWidget import *
12import orngTest, orngStat, OWGUI
13import time
14import warnings
15from orngWrap import PreprocessedLearner
16warnings.filterwarnings("ignore", "'id' is not a builtin attribute",
17                        orange.AttributeWarning)
18
19##############################################################################
20
21class Learner:
22    def __init__(self, learner, id):
23        self.learner = learner
24        self.name = learner.name
25        self.id = id
26        self.scores = []
27        self.results = None
28        self.time = time.time() # used to order the learners in the table
29
30class Score:
31    def __init__(self, name, label, f, show=True, cmBased=False):
32        self.name = name
33        self.label = label
34        self.f = f
35        self.show = show
36        self.cmBased = cmBased
37       
38def dispatch(score_desc, res, cm):
39    """ Dispatch the call to orngStat method.
40    """
41    return eval("orngStat." + score_desc.f)
42
43
44class OWTestLearners(OWWidget):
45    settingsList = ["nFolds", "pLearning", "pRepeat", "precision",
46                    "selectedCScores", "selectedRScores", "applyOnAnyChange",
47                    "resampling"]
48    contextHandlers = {"": DomainContextHandler("", ["targetClass"])}
49    callbackDeposit = []
50
51    cStatistics = [Score(*s) for s in [\
52        ('Classification accuracy', 'CA', 'CA(res)', True),
53        ('Sensitivity', 'Sens', 'sens(cm)', True, True),
54        ('Specificity', 'Spec', 'spec(cm)', True, True),
55        ('Area under ROC curve', 'AUC', 'AUC(res)', True),
56        ('Information score', 'IS', 'IS(res)', False),
57        ('F-measure', 'F1', 'F1(cm)', False, True),
58        ('Precision', 'Prec', 'precision(cm)', False, True),
59        ('Recall', 'Recall', 'recall(cm)', False, True),
60        ('Brier score', 'Brier', 'BrierScore(res)', True),
61        ('Matthews correlation coefficient', 'MCC', 'MCC(cm)', False, True)]]
62
63    rStatistics = [Score(*s) for s in [\
64        ("Mean squared error", "MSE", "MSE(res)", False),
65        ("Root mean squared error", "RMSE", "RMSE(res)"),
66        ("Mean absolute error", "MAE", "MAE(res)", False),
67        ("Relative squared error", "RSE", "RSE(res)", False),
68        ("Root relative squared error", "RRSE", "RRSE(res)"),
69        ("Relative absolute error", "RAE", "RAE(res)", False),
70        ("R-squared", "R2", "R2(res)")]]
71
72    resamplingMethods = ["Cross-validation", "Leave-one-out", "Random sampling",
73                         "Test on train data", "Test on test data"]
74
75    def __init__(self,parent=None, signalManager = None):
76        OWWidget.__init__(self, parent, signalManager, "TestLearners")
77
78        self.inputs = [("Data", ExampleTable, self.setData, Default), 
79                       ("Separate Test Data", ExampleTable, self.setTestData),
80                       ("Learner", orange.Learner, self.setLearner, Multiple + Default),
81                       ("Preprocess", PreprocessedLearner, self.setPreprocessor)]
82       
83        self.outputs = [("Evaluation Results", orngTest.ExperimentResults)]
84
85        # Settings
86        self.resampling = 0             # cross-validation
87        self.nFolds = 5                 # cross validation folds
88        self.pLearning = 70   # size of learning set when sampling [%]
89        self.pRepeat = 10
90        self.precision = 4
91        self.applyOnAnyChange = True
92        self.selectedCScores = [i for (i,s) in enumerate(self.cStatistics) if s.show]
93        self.selectedRScores = [i for (i,s) in enumerate(self.rStatistics) if s.show]
94        self.targetClass = 0
95        self.loadSettings()
96        self.resampling = 0             # cross-validation
97
98        self.stat = self.cStatistics
99
100        self.data = None                # input data set
101        self.testdata = None            # separate test data set
102        self.learners = {}              # set of learners (input)
103        self.results = None             # from orngTest
104        self.preprocessor = None
105
106        self.controlArea.layout().setSpacing(8)
107        # GUI
108        self.sBtns = OWGUI.radioButtonsInBox(self.controlArea, self, "resampling", 
109                                             box="Sampling",
110                                             btnLabels=self.resamplingMethods[:1],
111                                             callback=self.newsampling)
112        indent = OWGUI.checkButtonOffsetHint(self.sBtns.buttons[-1])
113       
114        ibox = OWGUI.widgetBox(OWGUI.indentedBox(self.sBtns, sep=indent))
115        OWGUI.spin(ibox, self, 'nFolds', 2, 100, step=1,
116                   label='Number of folds:',
117                   callback=lambda p=0: self.conditionalRecompute(p),
118                   keyboardTracking=False)
119       
120        OWGUI.separator(self.sBtns, height = 3)
121       
122        OWGUI.appendRadioButton(self.sBtns, self, "resampling", self.resamplingMethods[1])      # leave one out
123        OWGUI.separator(self.sBtns, height = 3)
124        OWGUI.appendRadioButton(self.sBtns, self, "resampling", self.resamplingMethods[2])      # random sampling
125                       
126        ibox = OWGUI.widgetBox(OWGUI.indentedBox(self.sBtns, sep=indent))
127        OWGUI.spin(ibox, self, 'pRepeat', 1, 100, step=1,
128                   label='Repeat train/test:',
129                   callback=lambda p=2: self.conditionalRecompute(p),
130                   keyboardTracking=False)
131       
132        OWGUI.widgetLabel(ibox, "Relative training set size:")
133       
134        OWGUI.hSlider(ibox, self, 'pLearning', minValue=10, maxValue=100,
135                      step=1, ticks=10, labelFormat="   %d%%",
136                      callback=lambda p=2: self.conditionalRecompute(p))
137       
138        OWGUI.separator(self.sBtns, height = 3)
139        OWGUI.appendRadioButton(self.sBtns, self, "resampling", self.resamplingMethods[3])  # test on train
140        OWGUI.separator(self.sBtns, height = 3)
141        OWGUI.appendRadioButton(self.sBtns, self, "resampling", self.resamplingMethods[4])  # test on test
142
143        self.trainDataBtn = self.sBtns.buttons[-2]
144        self.testDataBtn = self.sBtns.buttons[-1]
145        self.testDataBtn.setDisabled(True)
146       
147        OWGUI.separator(self.sBtns)
148        OWGUI.checkBox(self.sBtns, self, 'applyOnAnyChange',
149                       label="Apply on any change", callback=self.applyChange)
150        self.applyBtn = OWGUI.button(self.sBtns, self, "&Apply",
151                                     callback=lambda f=True: self.recompute(f))
152        self.applyBtn.setDisabled(True)
153
154        if self.resampling == 4:
155            self.resampling = 3
156
157        # statistics
158        self.statLayout = QStackedLayout()
159        self.cbox = OWGUI.widgetBox(self.controlArea, addToLayout=False)
160        self.cStatLabels = [s.name for s in self.cStatistics]
161        self.cstatLB = OWGUI.listBox(self.cbox, self, 'selectedCScores',
162                                     'cStatLabels', box = "Performance scores",
163                                     selectionMode = QListWidget.MultiSelection,
164                                     callback=self.newscoreselection)
165       
166        self.cbox.layout().addSpacing(8)
167        self.targetCombo = OWGUI.comboBox(self.cbox, self, "targetClass", orientation=0,
168                                        callback=[self.changedTarget],
169                                        box="Target class")
170
171        self.rStatLabels = [s.name for s in self.rStatistics]
172        self.rbox = OWGUI.widgetBox(self.controlArea, "Performance scores", addToLayout=False)
173        self.rstatLB = OWGUI.listBox(self.rbox, self, 'selectedRScores', 'rStatLabels',
174                                     selectionMode = QListWidget.MultiSelection,
175                                     callback=self.newscoreselection)
176       
177        self.statLayout.addWidget(self.cbox)
178        self.statLayout.addWidget(self.rbox)
179        self.controlArea.layout().addLayout(self.statLayout)
180       
181        self.statLayout.setCurrentWidget(self.cbox)
182
183        # score table
184        # table with results
185        self.g = OWGUI.widgetBox(self.mainArea, 'Evaluation Results')
186        self.tab = OWGUI.table(self.g, selectionMode = QTableWidget.NoSelection)
187
188        self.resize(680,470)
189
190    # scoring and painting of score table
191    def isclassification(self):
192        if not self.data or not self.data.domain.classVar:
193            return True
194        return self.data.domain.classVar.varType == orange.VarTypes.Discrete
195       
196    def paintscores(self):
197        """paints the table with evaluation scores"""
198
199        self.tab.setColumnCount(len(self.stat)+1)
200        self.tab.setHorizontalHeaderLabels(["Method"] + [s.label for s in self.stat])
201       
202        prec="%%.%df" % self.precision
203
204        learners = [(l.time, l) for l in self.learners.values()]
205        learners.sort()
206        learners = [lt[1] for lt in learners]
207
208        self.tab.setRowCount(len(self.learners))
209        for (i, l) in enumerate(learners):
210            OWGUI.tableItem(self.tab, i,0, l.name)
211           
212        for (i, l) in enumerate(learners):
213            if l.scores:
214                for j in range(len(self.stat)):
215                    if l.scores[j] is not None:
216                        OWGUI.tableItem(self.tab, i, j+1, prec % l.scores[j])
217                    else:
218                        OWGUI.tableItem(self.tab, i, j+1, "N/A")
219            else:
220                for j in range(len(self.stat)):
221                    OWGUI.tableItem(self.tab, i, j+1, "")
222       
223        # adjust the width of the score table cloumns
224        self.tab.resizeColumnsToContents()
225        self.tab.resizeRowsToContents()
226        usestat = [self.selectedRScores, self.selectedCScores][self.isclassification()]
227        for i in range(len(self.stat)):
228            if i not in usestat:
229                self.tab.hideColumn(i+1)
230
231    def sendReport(self):
232        exset = []
233        if self.resampling == 0:
234            exset = [("Folds", self.nFolds)]
235        elif self.resampling == 2:
236            exset = [("Repetitions", self.pRepeat), ("Proportion of training instances", "%i%%" % self.pLearning)]
237        else:
238            exset = []
239        self.reportSettings("Validation method",
240                            [("Method", self.resamplingMethods[self.resampling])]
241                            + exset +
242                            ([("Target class", self.data.domain.classVar.values[self.targetClass])] if self.data else []))
243       
244        self.reportData(self.data)
245
246        if self.data:       
247            self.reportSection("Results")
248            learners = [(l.time, l) for l in self.learners.values()]
249            learners.sort()
250            learners = [lt[1] for lt in learners]
251            usestat = [self.selectedRScores, self.selectedCScores][self.isclassification()]
252           
253            res = "<table><tr><th></th>"+"".join("<th><b>%s</b></th>" % hr for hr in [s.label for i, s in enumerate(self.stat) if i in usestat])+"</tr>"
254            for i, l in enumerate(learners):
255                res += "<tr><th><b>%s</b></th>" % l.name
256                if l.scores:
257                    for j in usestat:
258                        scr = l.scores[j]
259                        res += "<td>" + ("%.4f" % scr if scr is not None else "") + "</td>"
260                res += "</tr>"
261            res += "</table>"
262            self.reportRaw(res)
263           
264    def score(self, ids):
265        """compute scores for the list of learners"""
266        if (not self.data):
267            for id in ids:
268                self.learners[id].results = None
269                self.learners[id].scores = []
270            return
271        # test which learners can accept the given data set
272        # e.g., regressions can't deal with classification data
273        learners = []
274        used_ids = []
275        n = len(self.data.domain.attributes)*2
276        indices = orange.MakeRandomIndices2(p0=min(n, len(self.data)), stratified=orange.MakeRandomIndices2.StratifiedIfPossible)
277        new = self.data.selectref(indices(self.data))
278       
279        self.warning(0)
280        learner_exceptions = []
281        for l in [self.learners[id] for id in ids]:
282            learner = l.learner
283            if self.preprocessor:
284                learner = self.preprocessor.wrapLearner(learner)
285            try:
286                predictor = learner(new)
287                if predictor(new[0]).varType == new.domain.classVar.varType:
288                    learners.append(learner)
289                    used_ids.append(l.id)
290                else:
291                    l.scores = []
292                    l.results = None
293               
294            except Exception, ex:
295                learner_exceptions.append((l, ex))
296                l.scores = []
297                l.results = None
298       
299        if learner_exceptions:
300            text = "\n".join("Learner %s ends with exception: %s" % (l.name, str(ex)) \
301                             for l, ex in learner_exceptions)
302            self.warning(0, text)
303           
304        if not learners:
305            return
306
307        # computation of results (res, and cm if classification)
308        pb = None
309        if self.resampling==0:
310            pb = OWGUI.ProgressBar(self, iterations=self.nFolds)
311            res = orngTest.crossValidation(learners, self.data, folds=self.nFolds,
312                                           strat=orange.MakeRandomIndices.StratifiedIfPossible,
313                                           callback=pb.advance, storeExamples = True)
314            pb.finish()
315        elif self.resampling==1:
316            pb = OWGUI.ProgressBar(self, iterations=len(self.data))
317            res = orngTest.leaveOneOut(learners, self.data,
318                                       callback=pb.advance, storeExamples = True)
319            pb.finish()
320        elif self.resampling==2:
321            pb = OWGUI.ProgressBar(self, iterations=self.pRepeat)
322            res = orngTest.proportionTest(learners, self.data, self.pLearning/100.,
323                                          times=self.pRepeat, callback=pb.advance, storeExamples = True)
324            pb.finish()
325        elif self.resampling==3:
326            pb = OWGUI.ProgressBar(self, iterations=len(learners))
327            res = orngTest.learnAndTestOnLearnData(learners, self.data, storeExamples = True, callback=pb.advance)
328            pb.finish()
329           
330        elif self.resampling==4:
331            if not self.testdata:
332                for l in self.learners.values():
333                    l.scores = []
334                return
335            pb = OWGUI.ProgressBar(self, iterations=len(learners))
336            res = orngTest.learnAndTestOnTestData(learners, self.data, self.testdata, storeExamples = True, callback=pb.advance)
337            pb.finish()
338           
339        if self.isclassification():
340            cm = orngStat.computeConfusionMatrices(res, classIndex = self.targetClass)
341        else:
342            cm = None
343
344        if self.preprocessor: # Unwrap learners
345            learners = [l.wrappedLearner for l in learners]
346           
347        res.learners = learners
348       
349        for l in [self.learners[id] for id in ids]:
350            if l.learner in learners:
351                l.results = res
352            else:
353                l.results = None
354
355        self.error(range(len(self.stat)))
356        scores = []
357       
358        for i, s in enumerate(self.stat):
359            if s.cmBased:
360                try:
361                    scores.append(dispatch(s, res, cm))
362                except Exception, ex:
363                    self.error(i, "An error occurred while evaluating orngStat." + s.f + "on %s due to %s" % \
364                               (" ".join([l.name for l in learners]), ex.message))
365                    scores.append([None] * len(self.learners))
366            else:
367                scores_one = []
368                for res_one in orngStat.split_by_classifiers(res):
369                    try:
370                        scores_one.extend(dispatch(s, res_one, cm))
371                    except Exception, ex:
372                        self.error(i, "An error occurred while evaluating orngStat." + s.f + "on %s due to %s" % \
373                                   (res.classifierNames[0], ex.message))
374                        scores_one.append(None)
375                scores.append(scores_one)
376               
377        for i, (id, l) in enumerate(zip(used_ids, learners)):
378            self.learners[id].scores = [s[i] if s else None for s in scores]
379           
380        self.sendResults()
381
382    def recomputeCM(self):
383        if not self.results:
384            return
385        cm = orngStat.computeConfusionMatrices(self.results, classIndex = self.targetClass)
386        scores = [(indx, eval("orngStat." + s.f))
387                  for (indx, s) in enumerate(self.stat) if s.cmBased]
388        for (indx, score) in scores:
389            for (i, l) in enumerate([l for l in self.learners.values() if l.scores]):
390                learner_indx = self.results.learners.index(l.learner)
391                l.scores[indx] = score[learner_indx]
392               
393        self.paintscores()
394       
395    def clearScores(self, ids=None):
396        if ids is None:
397            ids = self.learners.keys()
398           
399        for id in ids:
400            self.learners[id].scores = []
401            self.learners[id].results = None
402       
403    # handle input signals
404    def setData(self, data):
405        """handle input train data set"""
406        self.closeContext()
407        self.data = self.isDataWithClass(data, checkMissing=True) and data or None
408        self.fillClassCombo()
409        if not self.data:
410            # data was removed, remove the scores
411            self.clearScores()
412            self.send("Evaluation Results", None)
413        else:
414            # new data has arrived
415            self.clearScores()
416           
417            self.data = orange.Filter_hasClassValue(self.data)
418            self.statLayout.setCurrentWidget(self.cbox if self.isclassification() else self.rbox)
419           
420            self.stat = [self.rStatistics, self.cStatistics][self.isclassification()]
421           
422            if self.learners:
423                self.score([l.id for l in self.learners.values()])
424
425        self.openContext("", data)
426        self.paintscores()
427
428    def setTestData(self, data):
429        """handle test data set"""
430        if data is None:
431            self.testdata = None
432        else:
433            self.testdata = orange.Filter_hasClassValue(data)
434        self.testDataBtn.setEnabled(self.testdata is not None)
435        if self.testdata is not None:
436            if self.resampling == 4:
437                if self.data:
438                    self.score([l.id for l in self.learners.values()])
439                else:
440                    for l in self.learners.values():
441                        l.scores = []
442                self.paintscores()
443        elif self.resampling == 4 and self.data:
444            # test data removed, switch to testing on train data
445            self.resampling = 3
446            self.recompute()
447
448    def fillClassCombo(self):
449        """upon arrival of new data appropriately set the target class combo"""
450        self.targetCombo.clear()
451        if not self.data or not self.data.domain.classVar or not self.isclassification():
452            return
453
454        domain = self.data.domain
455        self.targetCombo.addItems([str(v) for v in domain.classVar.values])
456       
457        if self.targetClass<len(domain.classVar.values):
458            self.targetCombo.setCurrentIndex(self.targetClass)
459        else:
460            self.targetCombo.setCurrentIndex(0)
461            self.targetClass=0
462
463    def setLearner(self, learner, id=None):
464        """add/remove a learner"""
465        if learner: # a new or updated learner
466            if id in self.learners: # updated learner
467                time = self.learners[id].time
468                self.learners[id] = Learner(learner, id)
469                self.learners[id].time = time
470            else: # new learner
471                self.learners[id] = Learner(learner, id)
472            if self.applyBtn.isEnabled():
473                self.recompute(True)
474            else:
475                self.score([id])
476        else: # remove a learner and corresponding results
477            if id in self.learners:
478                res = self.learners[id].results
479                if res and res.numberOfLearners > 1:
480                    old_learner = self.learners[id].learner
481                    indx = res.learners.index(old_learner)
482                    res.remove(indx)
483                    del res.learners[indx]
484                del self.learners[id]
485            self.sendResults()
486        self.paintscores()
487       
488    def setPreprocessor(self, pp):
489        self.preprocessor = pp
490        if self.learners:
491            self.score([l.id for l in self.learners.values()])
492            self.paintscores()
493
494    # handle output signals
495
496    def sendResults(self):
497        """commit evaluation results"""
498        # for each learner, we first find a list where a result is stored
499        # and remember the corresponding index
500
501        valid = [(l.results, l.results.learners.index(l.learner))
502                 for l in self.learners.values() if l.scores and l.results]
503           
504        if not (self.data and len(valid)):
505            self.send("Evaluation Results", None)
506            return
507
508        # find the result set for a largest number of learners
509        # and remove this set from the list of result sets
510        rlist = dict([(l.results,1) for l in self.learners.values() if l.scores and l.results]).keys()
511        rlen = [r.numberOfLearners for r in rlist]
512        results = rlist.pop(rlen.index(max(rlen)))
513       
514        for (i, l) in enumerate(results.learners):
515            if not l in [l.learner for l in self.learners.values()]:
516                results.remove(i)
517                del results.learners[i]
518           
519        for r in rlist:
520            for (i, l) in enumerate(r.learners):
521                learner_id = [l1.id for l1 in self.learners.values() if l1.learner is l][0]
522                if (r, i) in valid:
523                    results.add(r, i)
524                    results.learners.append(r.learners[i])
525                    self.learners[learner_id].results = results
526        self.send("Evaluation Results", results)
527        self.results = results
528
529    # signal processing
530
531    def newsampling(self):
532        """handle change of evaluation method"""
533        if not self.applyOnAnyChange:
534            self.applyBtn.setDisabled(self.applyOnAnyChange)
535        else:
536            if self.learners:
537                self.recompute()
538
539    def newscoreselection(self):
540        """handle change in set of scores to be displayed"""
541        usestat = [self.selectedRScores, self.selectedCScores][self.isclassification()]
542        for i in range(len(self.stat)):
543            if i in usestat:
544                self.tab.showColumn(i+1)
545                self.tab.resizeColumnToContents(i+1)
546            else:
547                self.tab.hideColumn(i+1)
548
549    def recompute(self, forced=False):
550        """recompute the scores for all learners,
551           if not forced, will do nothing but enable the Apply button"""
552        if self.applyOnAnyChange or forced:
553            self.score([l.id for l in self.learners.values()])
554            self.paintscores()
555            self.applyBtn.setDisabled(True)
556        else:
557            self.applyBtn.setEnabled(True)
558
559    def conditionalRecompute(self, option):
560        """calls recompute only if specific sampling option enabled"""
561        if self.resampling == option:
562            self.recompute(False)
563
564    def applyChange(self):
565        if self.applyOnAnyChange:
566            self.applyBtn.setDisabled(True)
567       
568    def changedTarget(self):
569        self.recomputeCM()
570
571##############################################################################
572# Test the widget, run from DOS prompt
573
574if __name__=="__main__":
575    a=QApplication(sys.argv)
576    ow=OWTestLearners()
577    ow.show()
578    a.exec_()
579
580    data1 = orange.ExampleTable(r'../../doc/datasets/voting')
581    data2 = orange.ExampleTable(r'../../golf')
582    datar = orange.ExampleTable(r'../../auto-mpg')
583    data3 = orange.ExampleTable(r'../../sailing-big')
584    data4 = orange.ExampleTable(r'../../sailing-test')
585
586    l1 = orange.MajorityLearner(); l1.name = '1 - Majority'
587
588    l2 = orange.BayesLearner()
589    l2.estimatorConstructor = orange.ProbabilityEstimatorConstructor_m(m=10)
590    l2.conditionalEstimatorConstructor = \
591        orange.ConditionalProbabilityEstimatorConstructor_ByRows(
592        estimatorConstructor = orange.ProbabilityEstimatorConstructor_m(m=10))
593    l2.name = '2 - NBC (m=10)'
594
595    l3 = orange.BayesLearner(); l3.name = '3 - NBC (default)'
596
597    l4 = orange.MajorityLearner(); l4.name = "4 - Majority"
598
599    import orngRegression as r
600    r5 = r.LinearRegressionLearner(name="0 - lin reg")
601
602    testcase = 4
603
604    if testcase == 0: # 1(UPD), 3, 4
605        ow.setData(data2)
606        ow.setLearner(r5, 5)
607        ow.setLearner(l1, 1)
608        ow.setLearner(l2, 2)
609        ow.setLearner(l3, 3)
610        l1.name = l1.name + " UPD"
611        ow.setLearner(l1, 1)
612        ow.setLearner(None, 2)
613        ow.setLearner(l4, 4)
614#        ow.setData(data1)
615#        ow.setData(datar)
616#        ow.setData(data1)
617    if testcase == 1: # data, but all learners removed
618        ow.setLearner(l1, 1)
619        ow.setLearner(l2, 2)
620        ow.setLearner(l1, 1)
621        ow.setLearner(None, 2)
622        ow.setData(data2)
623        ow.setLearner(None, 1)
624    if testcase == 2: # sends data, then learner, then removes the learner
625        ow.setData(data2)
626        ow.setLearner(l1, 1)
627        ow.setLearner(None, 1)
628    if testcase == 3: # regression first
629        ow.setData(datar)
630        ow.setLearner(r5, 5)
631    if testcase == 4: # separate train and test data
632        ow.setData(data3)
633        ow.setTestData(data4)
634        ow.setLearner(l2, 5)
635        ow.setTestData(None)
636
637    ow.saveSettings()
Note: See TracBrowser for help on using the repository browser.