source: orange/Orange/classification/svm/__init__.py @ 10542:7dde0640e266

Revision 10542:7dde0640e266, 25.8 KB checked in by anzeh <anze.staric@…>, 2 years ago (diff)

Moved preprocess from Orange to Orange.data.

Line 
1import math
2
3from collections import defaultdict
4
5import Orange.core
6import Orange.data
7import Orange.misc
8import Orange.feature
9
10import kernels
11import warnings
12
13from Orange.core import SVMLearner as _SVMLearner
14from Orange.core import SVMLearnerSparse as _SVMLearnerSparse
15from Orange.core import LinearClassifier, \
16                        LinearLearner, \
17                        SVMClassifier, \
18                        SVMClassifierSparse
19
20from Orange.data import preprocess
21
22from Orange import feature as variable
23
24from Orange.misc import _orange__new__
25
26def max_nu(data):
27    """
28    Return the maximum nu parameter for the given data table for
29    Nu_SVC learning.
30   
31    :param data: Data with discrete class variable
32    :type data: Orange.data.Table
33   
34    """
35    nu = 1.0
36    dist = list(Orange.core.Distribution(data.domain.classVar, data))
37    def pairs(seq):
38        for i, n1 in enumerate(seq):
39            for n2 in seq[i + 1:]:
40                yield n1, n2
41    return min([2.0 * min(n1, n2) / (n1 + n2) for n1, n2 in pairs(dist) \
42                if n1 != 0 and n2 != 0] + [nu])
43
44maxNu = max_nu
45
46class SVMLearner(_SVMLearner):
47    """
48    :param svm_type: the SVM type
49    :type svm_type: SVMLearner.SVMType
50    :param kernel_type: the kernel type
51    :type kernel_type: SVMLearner.Kernel
52    :param degree: kernel parameter (only for ``Polynomial``)
53    :type degree: int
54    :param gamma: kernel parameter; if 0, it is set to 1.0/#features (for ``Polynomial``, ``RBF`` and ``Sigmoid``)
55    :type gamma: float
56    :param coef0: kernel parameter (for ``Polynomial`` and ``Sigmoid``)
57    :type coef0: int
58    :param kernel_func: kernel function if ``kernel_type`` is
59        ``kernels.Custom``
60    :type kernel_func: callable object
61    :param C: C parameter (for ``C_SVC``, ``Epsilon_SVR`` and ``Nu_SVR``)
62    :type C: float
63    :param nu: Nu parameter (for ``Nu_SVC``, ``Nu_SVR`` and ``OneClass``)
64    :type nu: float
65    :param p: epsilon parameter (for ``Epsilon_SVR``)
66    :type p: float
67    :param cache_size: cache memory size in MB
68    :type cache_size: int
69    :param eps: tolerance of termination criterion
70    :type eps: float
71    :param probability: build a probability model
72    :type probability: bool
73    :param shrinking: use shrinking heuristics
74    :type shrinking: bool
75    :param weight: a list of class weights
76    :type weight: list
77
78    Example:
79   
80        >>> import Orange
81        >>> from Orange.classification import svm
82        >>> from Orange.evaluation import testing, scoring
83        >>> data = Orange.data.Table("vehicle.tab")
84        >>> learner = svm.SVMLearner()
85        >>> results = testing.cross_validation([learner], data, folds=5)
86        >>> print scoring.CA(results)[0]
87        0.789613644274
88   
89    """
90    __new__ = _orange__new__(_SVMLearner)
91
92    C_SVC = _SVMLearner.C_SVC
93    Nu_SVC = _SVMLearner.Nu_SVC
94    OneClass = _SVMLearner.OneClass
95    Nu_SVR = _SVMLearner.Nu_SVR
96    Epsilon_SVR = _SVMLearner.Epsilon_SVR
97
98    @Orange.misc.deprecated_keywords({"kernelFunc": "kernel_func"})
99    def __init__(self, svm_type=Nu_SVC, kernel_type=kernels.RBF,
100                 kernel_func=None, C=1.0, nu=0.5, p=0.1, gamma=0.0, degree=3,
101                 coef0=0, shrinking=True, probability=True, verbose=False,
102                 cache_size=200, eps=0.001, normalization=True,
103                 weight=[], **kwargs):
104        self.svm_type = svm_type
105        self.kernel_type = kernel_type
106        self.kernel_func = kernel_func
107        self.C = C
108        self.nu = nu
109        self.p = p
110        self.gamma = gamma
111        self.degree = degree
112        self.coef0 = coef0
113        self.shrinking = shrinking
114        self.probability = probability
115        self.verbose = verbose
116        self.cache_size = cache_size
117        self.eps = eps
118        self.normalization = normalization
119        for key, val in kwargs.items():
120            setattr(self, key, val)
121        self.learner = Orange.core.SVMLearner(**kwargs)
122        self.weight = weight
123
124    max_nu = staticmethod(max_nu)
125
126    def __call__(self, data, weight=0):
127        """Construct a SVM classifier
128       
129        :param table: data with continuous features
130        :type table: Orange.data.Table
131       
132        :param weight: ignored (required due to base class signature);
133        """
134
135        examples = Orange.core.Preprocessor_dropMissingClasses(data)
136        class_var = examples.domain.class_var
137        if len(examples) == 0:
138            raise ValueError("Example table is without any defined classes")
139
140        # Fix the svm_type parameter if we have a class_var/svm_type mismatch
141        if self.svm_type in [0, 1] and \
142            isinstance(class_var, Orange.feature.Continuous):
143            self.svm_type += 3
144            #raise AttributeError, "Cannot learn a discrete classifier from non descrete class data. Use EPSILON_SVR or NU_SVR for regression"
145        if self.svm_type in [3, 4] and \
146            isinstance(class_var, Orange.feature.Discrete):
147            self.svm_type -= 3
148            #raise AttributeError, "Cannot do regression on descrete class data. Use C_SVC or NU_SVC for classification"
149        if self.kernel_type == kernels.Custom and not self.kernel_func:
150            raise ValueError("Custom kernel function not supplied")
151
152        import warnings
153
154        nu = self.nu
155        if self.svm_type == SVMLearner.Nu_SVC: #is nu feasible
156            max_nu = self.max_nu(examples)
157            if self.nu > max_nu:
158                if getattr(self, "verbose", 0):
159                    warnings.warn("Specified nu %.3f is infeasible. \
160                    Setting nu to %.3f" % (self.nu, max_nu))
161                nu = max(max_nu - 1e-7, 0.0)
162
163        for name in ["svm_type", "kernel_type", "kernel_func", "C", "nu", "p",
164                     "gamma", "degree", "coef0", "shrinking", "probability",
165                     "verbose", "cache_size", "eps"]:
166            setattr(self.learner, name, getattr(self, name))
167        self.learner.nu = nu
168        self.learner.set_weights(self.weight)
169
170        if self.svm_type == SVMLearner.OneClass and self.probability:
171            self.learner.probability = False
172            warnings.warn("One-class SVM probability output not supported yet.")
173        return self.learn_classifier(examples)
174
175    def learn_classifier(self, data):
176        if self.normalization:
177            data = self._normalize(data)
178            svm = self.learner(data)
179            return SVMClassifierWrapper(svm)
180        return self.learner(data)
181
182    @Orange.misc.deprecated_keywords({"progressCallback": "progress_callback"})
183    def tune_parameters(self, data, parameters=None, folds=5, verbose=0,
184                       progress_callback=None):
185        """Tune the ``parameters`` on the given ``data`` using
186        internal cross validation.
187       
188        :param data: data for parameter tuning
189        :type data: Orange.data.Table
190        :param parameters: names of parameters to tune
191            (default: ["nu", "C", "gamma"])
192        :type parameters: list of strings
193        :param folds: number of folds for internal cross validation
194        :type folds: int
195        :param verbose: set verbose output
196        :type verbose: bool
197        :param progress_callback: callback function for reporting progress
198        :type progress_callback: callback function
199           
200        Here is example of tuning the `gamma` parameter using
201        3-fold cross validation. ::
202
203            svm = Orange.classification.svm.SVMLearner()
204            svm.tune_parameters(table, parameters=["gamma"], folds=3)
205                   
206        """
207
208        import orngWrap
209
210        if parameters is None:
211            parameters = ["nu", "C", "gamma"]
212
213        searchParams = []
214        normalization = self.normalization
215        if normalization:
216            data = self._normalize(data)
217            self.normalization = False
218        if self.svm_type in [SVMLearner.Nu_SVC, SVMLearner.Nu_SVR] \
219                    and "nu" in parameters:
220            numOfNuValues = 9
221            if isinstance(data.domain.class_var, variable.Discrete):
222                max_nu = max(self.max_nu(data) - 1e-7, 0.0)
223            else:
224                max_nu = 1.0
225            searchParams.append(("nu", [i / 10.0 for i in range(1, 9) if \
226                                        i / 10.0 < max_nu] + [max_nu]))
227        elif "C" in parameters:
228            searchParams.append(("C", [2 ** a for a in  range(-5, 15, 2)]))
229        if self.kernel_type == 2 and "gamma" in parameters:
230            searchParams.append(("gamma", [2 ** a for a in range(-5, 5, 2)] + [0]))
231        tunedLearner = orngWrap.TuneMParameters(object=self,
232                            parameters=searchParams,
233                            folds=folds,
234                            returnWhat=orngWrap.TuneMParameters.returnLearner,
235                            progressCallback=progress_callback
236                            if progress_callback else lambda i:None)
237        tunedLearner(data, verbose=verbose)
238        if normalization:
239            self.normalization = normalization
240
241    def _normalize(self, data):
242        dc = preprocess.DomainContinuizer()
243        dc.class_treatment = preprocess.DomainContinuizer.Ignore
244        dc.continuous_treatment = preprocess.DomainContinuizer.NormalizeBySpan
245        dc.multinomial_treatment = preprocess.DomainContinuizer.NValues
246        newdomain = dc(data)
247        return data.translate(newdomain)
248
249SVMLearner = Orange.misc.deprecated_members({
250    "learnClassifier": "learn_classifier",
251    "tuneParameters": "tune_parameters",
252    "kernelFunc" : "kernel_func",
253    },
254    wrap_methods=["__init__", "tune_parameters"])(SVMLearner)
255
256class SVMClassifierWrapper(Orange.core.SVMClassifier):
257    def __new__(cls, wrapped):
258        return Orange.core.SVMClassifier.__new__(cls, name=wrapped.name)
259
260    def __init__(self, wrapped):
261        self.wrapped = wrapped
262        for name, val in wrapped.__dict__.items():
263            self.__dict__[name] = val
264
265    def __call__(self, example, what=Orange.core.GetValue):
266        example = Orange.data.Instance(self.wrapped.domain, example)
267        return self.wrapped(example, what)
268
269    def class_distribution(self, example):
270        example = Orange.data.Instance(self.wrapped.domain, example)
271        return self.wrapped.class_distribution(example)
272
273    def get_decision_values(self, example):
274        example = Orange.data.Instance(self.wrapped.domain, example)
275        return self.wrapped.get_decision_values(example)
276
277    def get_model(self):
278        return self.wrapped.get_model()
279
280    def __reduce__(self):
281        return SVMClassifierWrapper, (self.wrapped,), dict([(name, val) \
282            for name, val in self.__dict__.items() \
283            if name not in self.wrapped.__dict__])
284
285SVMClassifierWrapper = Orange.misc.deprecated_members({
286    "classDistribution": "class_distribution",
287    "getDecisionValues": "get_decision_values",
288    "getModel" : "get_model",
289    })(SVMClassifierWrapper)
290
291class SVMLearnerSparse(SVMLearner):
292
293    """
294    A :class:`SVMLearner` that learns from data stored in meta
295    attributes. Meta attributes do not need to be registered with the
296    data set domain, or present in all data instances.
297    """
298
299    @Orange.misc.deprecated_keywords({"useNonMeta": "use_non_meta"})
300    def __init__(self, **kwds):
301        SVMLearner.__init__(self, **kwds)
302        self.use_non_meta = kwds.get("use_non_meta", False)
303        self.learner = Orange.core.SVMLearnerSparse(**kwds)
304
305    def _normalize(self, data):
306        if self.use_non_meta:
307            dc = preprocess.DomainContinuizer()
308            dc.class_treatment = preprocess.DomainContinuizer.Ignore
309            dc.continuous_treatment = preprocess.DomainContinuizer.NormalizeBySpan
310            dc.multinomial_treatment = preprocess.DomainContinuizer.NValues
311            newdomain = dc(data)
312            data = data.translate(newdomain)
313        return data
314
315class SVMLearnerEasy(SVMLearner):
316
317    """A class derived from :obj:`SVMLearner` that automatically
318    scales the data and performs parameter optimization using
319    :func:`SVMLearner.tune_parameters`. The procedure is similar to
320    that implemented in easy.py script from the LibSVM package.
321   
322    """
323
324    def __init__(self, **kwds):
325        self.folds = 4
326        self.verbose = 0
327        SVMLearner.__init__(self, **kwds)
328        self.learner = SVMLearner(**kwds)
329
330    def learn_classifier(self, data):
331        transformer = preprocess.DomainContinuizer()
332        transformer.multinomialTreatment = preprocess.DomainContinuizer.NValues
333        transformer.continuousTreatment = \
334            preprocess.DomainContinuizer.NormalizeBySpan
335        transformer.classTreatment = preprocess.DomainContinuizer.Ignore
336        newdomain = transformer(data)
337        newexamples = data.translate(newdomain)
338        #print newexamples[0]
339        params = {}
340        parameters = []
341        self.learner.normalization = False ## Normalization already done
342
343        if self.svm_type in [1, 4]:
344            numOfNuValues = 9
345            if self.svm_type == SVMLearner.Nu_SVC:
346                max_nu = max(self.max_nu(newexamples) - 1e-7, 0.0)
347            else:
348                max_nu = 1.0
349            parameters.append(("nu", [i / 10.0 for i in range(1, 9) \
350                                      if i / 10.0 < max_nu] + [max_nu]))
351        else:
352            parameters.append(("C", [2 ** a for a in  range(-5, 15, 2)]))
353        if self.kernel_type == 2:
354            parameters.append(("gamma", [2 ** a for a in range(-5, 5, 2)] + [0]))
355        import orngWrap
356        tunedLearner = orngWrap.TuneMParameters(object=self.learner,
357                                                parameters=parameters,
358                                                folds=self.folds)
359
360        return SVMClassifierWrapper(tunedLearner(newexamples,
361                                                 verbose=self.verbose))
362
363class SVMLearnerSparseClassEasy(SVMLearnerEasy, SVMLearnerSparse):
364    def __init__(self, **kwds):
365        SVMLearnerSparse.__init__(self, **kwds)
366
367def default_preprocessor():
368    # Construct and return a default preprocessor for use by
369    # Orange.core.LinearLearner learner.
370    impute = preprocess.Impute()
371    cont = preprocess.Continuize(multinomialTreatment=
372                                   preprocess.DomainContinuizer.AsOrdinal)
373    preproc = preprocess.PreprocessorList(preprocessors=
374                                            [impute, cont])
375    return preproc
376
377class LinearSVMLearner(Orange.core.LinearLearner):
378    """Train a linear SVM model."""
379
380    L2R_L2LOSS_DUAL = Orange.core.LinearLearner.L2R_L2Loss_SVC_Dual
381    L2R_L2LOSS = Orange.core.LinearLearner.L2R_L2Loss_SVC
382    L2R_L1LOSS_DUAL = Orange.core.LinearLearner.L2R_L1Loss_SVC_Dual
383    L2R_L1LOSS_DUAL = Orange.core.LinearLearner.L2R_L2Loss_SVC_Dual
384    L1R_L2LOSS = Orange.core.LinearLearner.L1R_L2Loss_SVC
385
386    __new__ = _orange__new__(base=Orange.core.LinearLearner)
387
388    def __init__(self, solver_type=L2R_L2LOSS_DUAL, C=1.0, eps=0.01, **kwargs):
389        """
390        :param solver_type: One of the following class constants: ``LR2_L2LOSS_DUAL``, ``L2R_L2LOSS``, ``LR2_L1LOSS_DUAL``, ``L2R_L1LOSS`` or ``L1R_L2LOSS``
391       
392        :param C: Regularization parameter (default 1.0)
393        :type C: float 
394       
395        :param eps: Stopping criteria (default 0.01)
396        :type eps: float
397         
398        """
399        self.solver_type = solver_type
400        self.eps = eps
401        self.C = C
402        for name, val in kwargs.items():
403            setattr(self, name, val)
404        if self.solver_type not in [self.L2R_L2LOSS_DUAL, self.L2R_L2LOSS,
405                self.L2R_L1LOSS_DUAL, self.L2R_L1LOSS_DUAL, self.L1R_L2LOSS]:
406            pass
407#            raise ValueError("Invalid solver_type parameter.")
408
409        self.preproc = default_preprocessor()
410
411    def __call__(self, instances, weight_id=None):
412        instances = self.preproc(instances)
413        classifier = super(LinearSVMLearner, self).__call__(instances, weight_id)
414        return classifier
415
416LinearLearner = LinearSVMLearner
417
418class MultiClassSVMLearner(Orange.core.LinearLearner):
419    """ Multi-class SVM (Crammer and Singer) from the `LIBLINEAR`_ library.
420    """
421    __new__ = _orange__new__(base=Orange.core.LinearLearner)
422
423    def __init__(self, C=1.0, eps=0.01, **kwargs):
424        """\
425        :param C: Regularization parameter (default 1.0)
426        :type C: float 
427       
428        :param eps: Stopping criteria (default 0.01)
429        :type eps: float
430       
431        """
432        self.C = C
433        self.eps = eps
434        for name, val in kwargs.items():
435            setattr(self, name, val)
436
437        self.solver_type = self.MCSVM_CS
438        self.preproc = default_preprocessor()
439
440    def __call__(self, instances, weight_id=None):
441        instances = self.preproc(instances)
442        classifier = super(MultiClassSVMLearner, self).__call__(instances, weight_id)
443        return classifier
444
445#TODO: Unified way to get attr weights for linear SVMs.
446
447def get_linear_svm_weights(classifier, sum=True):
448    """Extract attribute weights from the linear SVM classifier.
449   
450    For multi class classification, the result depends on the argument
451    :obj:`sum`. If ``True`` (default) the function computes the
452    squared sum of the weights over all binary one vs. one
453    classifiers. If :obj:`sum` is ``False`` it returns a list of
454    weights for each individual binary classifier (in the order of
455    [class1 vs class2, class1 vs class3 ... class2 vs class3 ...]).
456       
457    """
458
459    def update_weights(w, key, val, mul):
460        if key in w:
461            w[key] += mul * val
462        else:
463            w[key] = mul * val
464
465    def to_float(val):
466        return float(val) if not val.isSpecial() else 0.0
467
468    SVs = classifier.support_vectors
469    weights = []
470
471    class_var = SVs.domain.class_var
472    if classifier.svm_type in [SVMLearner.C_SVC, SVMLearner.Nu_SVC]:
473        classes = class_var.values
474    else:
475        classes = [""]
476    if len(classes) > 1:
477        sv_ranges = [(0, classifier.nSV[0])]
478        for n in classifier.nSV[1:]:
479            sv_ranges.append((sv_ranges[-1][1], sv_ranges[-1][1] + n))
480    else:
481        sv_ranges = [(0, len(SVs))]
482
483    for i in range(len(classes) - 1):
484        for j in range(i + 1, len(classes)):
485            w = {}
486            coef_ind = j - 1
487            for sv_ind in range(*sv_ranges[i]):
488                attributes = SVs.domain.attributes + \
489                SVs[sv_ind].getmetas(False, Orange.feature.Descriptor).keys()
490                for attr in attributes:
491                    if attr.varType == Orange.feature.Type.Continuous:
492                        update_weights(w, attr, to_float(SVs[sv_ind][attr]), \
493                                       classifier.coef[coef_ind][sv_ind])
494            coef_ind = i
495            for sv_ind in range(*sv_ranges[j]):
496                attributes = SVs.domain.attributes + \
497                SVs[sv_ind].getmetas(False, Orange.feature.Descriptor).keys()
498                for attr in attributes:
499                    if attr.varType == Orange.feature.Type.Continuous:
500                        update_weights(w, attr, to_float(SVs[sv_ind][attr]), \
501                                       classifier.coef[coef_ind][sv_ind])
502            weights.append(w)
503
504    if sum:
505        scores = defaultdict(float)
506
507        for w in weights:
508            for attr, w_attr in w.items():
509                scores[attr] += w_attr ** 2
510        for key in scores:
511            scores[key] = math.sqrt(scores[key])
512        return scores
513    else:
514        return weights
515
516getLinearSVMWeights = get_linear_svm_weights
517
518def example_weighted_sum(example, weights):
519    sum = 0
520    for attr, w in weights.items():
521        sum += float(example[attr]) * w
522    return sum
523
524exampleWeightedSum = example_weighted_sum
525
526class ScoreSVMWeights(Orange.feature.scoring.Score):
527    """
528    Score a feature by the squared sum of weights using a linear SVM
529    classifier.
530       
531    Example:
532   
533        >>> score = Orange.classification.svm.ScoreSVMWeights()
534        >>> for feature in table.domain.features:
535        ...     print "%15s: %.3f" % (feature.name, score(feature, table))
536            compactness: 0.019
537            circularity: 0.026
538        distance circularity: 0.007
539           radius ratio: 0.010
540        pr.axis aspect ratio: 0.076
541        max.length aspect ratio: 0.010
542          scatter ratio: 0.046
543          elongatedness: 0.094
544        pr.axis rectangularity: 0.006
545        max.length rectangularity: 0.031
546        scaled variance along major axis: 0.001
547        scaled variance along minor axis: 0.000
548        scaled radius of gyration: 0.002
549        skewness about major axis: 0.004
550        skewness about minor axis: 0.003
551        kurtosis about minor axis: 0.001
552        kurtosis about major axis: 0.060
553          hollows ratio: 0.028
554             
555    """
556
557    def __new__(cls, attr=None, data=None, weight_id=None, **kwargs):
558        self = Orange.feature.scoring.Score.__new__(cls, **kwargs)
559        if data is not None and attr is not None:
560            self.__init__(**kwargs)
561            return self.__call__(attr, data, weight_id)
562        else:
563            return self
564
565    def __reduce__(self):
566        return ScoreSVMWeights, (), dict(self.__dict__)
567
568    def __init__(self, learner=None, **kwargs):
569        """
570        :param learner: Learner used for weight estimation
571            (default LinearSVMLearner(solver_type=L2Loss_SVM_Dual))
572        :type learner: Orange.core.LinearLearner
573       
574        """
575        if learner:
576            self.learner = learner
577        else:
578            self.learner = LinearSVMLearner(solver_type=
579                                    LinearSVMLearner.L2R_L2LOSS_DUAL)
580
581        self._cached_examples = None
582
583    def __call__(self, attr, data, weight_id=None):
584        if data is self._cached_examples:
585            weights = self._cached_weights
586        else:
587            classifier = self.learner(data, weight_id)
588            self._cached_examples = data
589            import numpy
590            weights = numpy.array(classifier.weights)
591            weights = numpy.sum(weights ** 2, axis=0)
592            weights = dict(zip(data.domain.attributes, weights))
593            self._cached_weights = weights
594        return weights.get(attr, 0.0)
595
596MeasureAttribute_SVMWeights = ScoreSVMWeights
597
598class RFE(object):
599
600    """Iterative feature elimination based on weights computed by
601    linear SVM.
602   
603    Example::
604   
605        import Orange
606        table = Orange.data.Table("vehicle.tab")
607        l = Orange.classification.svm.SVMLearner(
608            kernel_type=Orange.classification.svm.kernels.Linear,
609            normalization=False) # normalization=False will not change the domain
610        rfe = Orange.classification.svm.RFE(l)
611        data_subset_of_features = rfe(table, 5)
612       
613    """
614
615    def __init__(self, learner=None):
616        self.learner = learner or SVMLearner(kernel_type=
617                            kernels.Linear, normalization=False)
618
619    @Orange.misc.deprecated_keywords({"progressCallback": "progress_callback", "stopAt": "stop_at" })
620    def get_attr_scores(self, data, stop_at=0, progress_callback=None):
621        """Return a dictionary mapping attributes to scores.
622        A score is a step number at which the attribute
623        was removed from the recursive evaluation.
624       
625        """
626        iter = 1
627        attrs = data.domain.attributes
628        attrScores = {}
629
630        while len(attrs) > stop_at:
631            weights = get_linear_svm_weights(self.learner(data), sum=False)
632            if progress_callback:
633                progress_callback(100. * iter / (len(attrs) - stop_at))
634            score = dict.fromkeys(attrs, 0)
635            for w in weights:
636                for attr, wAttr in w.items():
637                    score[attr] += wAttr ** 2
638            score = score.items()
639            score.sort(lambda a, b:cmp(a[1], b[1]))
640            numToRemove = max(int(len(attrs) * 1.0 / (iter + 1)), 1)
641            for attr, s in  score[:numToRemove]:
642                attrScores[attr] = len(attrScores)
643            attrs = [attr for attr, s in score[numToRemove:]]
644            if attrs:
645                data = data.select(attrs + [data.domain.classVar])
646            iter += 1
647        return attrScores
648
649    @Orange.misc.deprecated_keywords({"numSelected": "num_selected", "progressCallback": "progress_callback"})
650    def __call__(self, data, num_selected=20, progress_callback=None):
651        """Return a new dataset with only `num_selected` best scoring attributes
652       
653        :param data: Data
654        :type data: Orange.data.Table
655        :param num_selected: number of features to preserve
656        :type num_selected: int
657       
658        """
659        scores = self.get_attr_scores(data, progress_callback=progress_callback)
660        scores = sorted(scores.items(), key=lambda item: item[1])
661
662        scores = dict(scores[-num_selected:])
663        attrs = [attr for attr in data.domain.attributes if attr in scores]
664        domain = Orange.data.Domain(attrs, data.domain.classVar)
665        domain.addmetas(data.domain.getmetas())
666        data = Orange.data.Table(domain, data)
667        return data
668
669RFE = Orange.misc.deprecated_members({
670    "getAttrScores": "get_attr_scores"},
671    wrap_methods=["get_attr_scores", "__call__"])(RFE)
672
673def example_table_to_svm_format(table, file):
674    warnings.warn("Deprecated. Use table_to_svm_format", DeprecationWarning)
675    table_to_svm_format(table, file)
676
677exampleTableToSVMFormat = example_table_to_svm_format
678
679def table_to_svm_format(data, file):
680    """Save :obj:`Orange.data.Table` to a format used by LibSVM.
681   
682    :param data: Data
683    :type data: Orange.data.Table
684    :param file: file pointer
685    :type file: file
686   
687    """
688
689    attrs = data.domain.attributes + data.domain.getmetas().values()
690    attrs = [attr for attr in attrs if attr.varType
691             in [Orange.feature.Type.Continuous,
692                 Orange.feature.Type.Discrete]]
693    cv = data.domain.classVar
694
695    for ex in data:
696        if cv.varType == Orange.feature.Type.Discrete:
697            file.write(str(int(ex[cv])))
698        else:
699            file.write(str(float(ex[cv])))
700
701        for i, attr in enumerate(attrs):
702            if not ex[attr].isSpecial():
703                file.write(" " + str(i + 1) + ":" + str(float(ex[attr])))
704        file.write("\n")
705
706tableToSVMFormat = table_to_svm_format
Note: See TracBrowser for help on using the repository browser.