Changeset 8201:c0c11f05fcda in orange


Ignore:
Timestamp:
08/17/11 18:46:18 (3 years ago)
Author:
ales_erjavec <ales.erjavec@…>
Branch:
default
Convert:
7003af78692a10afa48c0769a1e73b01de1721d7
Message:

Documentation update for Orange.regression.earth.

Location:
orange
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • orange/Orange/regression/earth.py

    r8195 r8201  
    2020    >>> from Orange.regression import earth 
    2121    >>> data = Orange.data.Table("housing") 
    22     >>> c = earth.EarthLearner(data, degree=2, terms=5) 
     22    >>> c = earth.EarthLearner(data, degree=2) 
    2323    >>> c.print_model() 
    2424    MEDV = 
    25        23.710 
    26        +9.379 * max(0, RM - 6.431) 
    27        +1.714 * max(0, 6.431 - RM) 
    28        -0.656 * max(0, LSTAT - 6.120) 
    29        +2.748 * max(0, 6.120 - LSTAT) 
     25       23.587 
     26       +11.896 * max(0, RM - 6.431) 
     27       +1.142 * max(0, 6.431 - RM) 
     28       -0.612 * max(0, LSTAT - 6.120) 
     29       -228.795 * max(0, NOX - 0.647) * max(0, RM - 6.431) 
     30       +0.023 * max(0, TAX - 307.000) * max(0, 6.120 - LSTAT) 
     31       +0.029 * max(0, 307.000 - TAX) * max(0, 6.120 - LSTAT) 
    3032        
    3133    >>>  
     
    3840    :members: 
    3941 
     42 
    4043Utility functions 
    4144----------------- 
     
    4649 
    4750.. autofunction:: bagged_evimp 
     51 
     52.. autoclass:: ScoreEarthImportance 
    4853 
    4954""" 
     
    6671 
    6772def expand_discrete(var): 
     73    """ Expand a discrete variable ``var`` returning one continuous indicator 
     74    variable for each value of ``var`` (if the number of values is grater 
     75    then 2 else return only one indicator variable). 
     76     
     77    """ 
    6878    if len(var.values) > 2: 
    6979        values = var.values 
     
    8393     
    8494class EarthLearner(Orange.core.LearnerFD): 
    85     """ Earth learner class. 
     95    """ Earth learner class. Supports both regression and classification 
     96    problems. In case of classification the class values are expanded into  
     97    continuous indicator columns (one for each value unless the number of  
     98    values is grater then 2), and a multi response model is learned on these 
     99    new columns. The resulting classifier will then use the computed response 
     100    values on new examples to select the final predicted class.  
     101      
    86102    """ 
    87103    def __new__(cls, examples=None, weight_id=None, **kwargs): 
     
    120136            pruning (default None - no limit). 
    121137        :type pruned_terms: int 
    122         :param scale_resp: Scale responses prior to forward pass. 
     138        :param scale_resp: Scale responses prior to forward pass (default 
     139            True - ignored for multi response models). 
    123140        :type scale_resp: bool 
    124         :param store_examples: Store training examples in the model (default True). 
     141        :param store_examples: Store training examples in the model 
     142            (default True). 
    125143        :type store_examples: bool 
    126144        :param multi_label: If True build a multi label model (default False). 
    127145        :type multi_label: bool   
    128146          
    129         .. todo:: min_span, prunning_method 
     147        .. todo:: min_span, prunning_method (need Leaps like functionality, 
     148            currently only eval_subsets_using_xtx is implemented).  
    130149         
    131150        """ 
     
    147166         
    148167        impute = Preprocessor_impute() 
    149         cont = Preprocessor_continuize(multinomialTreatment=DomainContinuizer.AsOrdinal) 
     168        cont = Preprocessor_continuize(multinomialTreatment= 
     169                                       DomainContinuizer.AsOrdinal) 
    150170        self.preproc = Preprocessor_preprocessorList(preprocessors=\ 
    151171                                                     [impute, cont]) 
     
    285305        If table is not supplied the base matrix of the training examples  
    286306        is returned. 
     307        Base matrix is a len(examples) x num_terms matrix of computed values 
     308        of terms in the model (not multiplied by beta) for each example. 
    287309         
    288310        :param examples: Input examples for the base matrix. 
     
    332354         
    333355        :param used_only: if True return only used attributes 
     356         
     357 
    334358          
    335359        """   
     
    612636    """ Do pruning pass 
    613637     
    614     .. todo:: leaps 
     638    .. todo:: pruned_terms, Leaps 
    615639     
    616640    """ 
     
    629653     
    630654    return used, subsets, rss_vec, gcv_vec 
    631      
    632 """\ 
    633 Variable importance estimation 
    634 ------------------------------ 
    635 """ 
    636  
    637 from collections import defaultdict 
    638  
    639 def collect_source(vars): 
    640     """ Given a list of variables ``var``, return a mapping from source 
    641     variables (``source_variable`` or ``get_value_from.variable`` members) 
    642     back to the variables in ``vars`` (assumes the default preprocessor in 
    643     EarthLearner). 
    644      
    645     """ 
    646     source = defaultdict(list) 
    647     for var in vars: 
    648         svar = None 
    649         if var.source_variable: 
    650             source[var.source_variable].append(var) 
    651         elif isinstance(var.get_value_from, Orange.core.ClassifierFromVar): 
    652             source[var.get_value_from.variable].append(var) 
    653         elif isinstance(var.get_value_from, Orange.core.ImputeClassifier): 
    654             source[var.get_value_from.classifier_from_var.variable].append(var) 
    655         else: 
    656             source[var].append(var) 
    657     return dict(source) 
    658  
    659 def map_to_source_var(var, sources): 
    660     """  
    661     """ 
    662     if var in sources: 
    663         return var 
    664     elif var.source_variable in sources: 
    665         return var.source_variable 
    666     elif isinstance(var.get_value_from, Orange.core.ClassifierFromVar): 
    667         return map_to_source_var(var.get_value_from.variable, sources) 
    668     elif isinstance(var.get_value_from, Orange.core.ImputeClassifier): 
    669         var = var.get_value_from.classifier_from_var.variable 
    670         return map_to_source_var(var, sources) 
    671     else: 
    672         return None 
    673      
    674 def evimp(model, used_only=True): 
    675     """ Return the estimated variable importance for the model. 
    676      
    677     :param model: Earth model. 
    678     :type model: `EarthClassifier` 
    679      
    680     """ 
    681     if model.subsets is None: 
    682         raise ValueError("No subsets. Use the learner with 'prune=True'.") 
    683      
    684     subsets = model.subsets 
    685     n_subsets = numpy.sum(model.best_set) 
    686      
    687     rss = -numpy.diff(model.rss_per_subset) 
    688     gcv = -numpy.diff(model.gcv_per_subset) 
    689     attributes = list(model.domain.variables) 
    690      
    691     attr2ind = dict(zip(attributes, range(len(attributes)))) 
    692     importances = numpy.zeros((len(attributes), 4)) 
    693     importances[:, 0] = range(len(attributes)) 
    694      
    695     for i in range(1, n_subsets): 
    696         term_subset = subsets[i, :i + 1] 
    697         used_attributes = reduce(set.union, [model.used_attributes(term) \ 
    698                                              for term in term_subset], set()) 
    699         for attr in used_attributes: 
    700             importances[attr2ind[attr]][1] += 1.0 
    701             importances[attr2ind[attr]][2] += gcv[i - 1] 
    702             importances[attr2ind[attr]][3] += rss[i - 1] 
    703     imp_min = numpy.min(importances[:, [2, 3]], axis=0) 
    704     imp_max = numpy.max(importances[:, [2, 3]], axis=0) 
    705      
    706     #Normalize importances. 
    707     importances[:, [2, 3]] = 100.0 * (importances[:, [2, 3]] \ 
    708                             - [imp_min]) / ([imp_max - imp_min]) 
    709      
    710     importances = list(importances) 
    711     # Sort by n_subsets and gcv. 
    712     importances = sorted(importances, key=lambda row: (row[1], row[2]), 
    713                          reverse=True) 
    714     importances = numpy.array(importances) 
    715      
    716     if used_only: 
    717         importances = importances[importances[:,1] > 0.0] 
    718      
    719     res = [(attributes[int(row[0])], tuple(row[1:])) for row in importances] 
    720     return res 
    721  
    722  
    723 def plot_evimp(evimp): 
    724     """ Plot the return value from :obj:`EarthClassifier.evimp` call. 
    725     """ 
    726     import pylab 
    727     fig = pylab.figure() 
    728     axes1 = fig.add_subplot(111) 
    729     attrs = [a for a, _ in evimp] 
    730     imp = [s for _, s in evimp] 
    731     imp = numpy.array(imp) 
    732     X = range(len(attrs)) 
    733     l1 = axes1.plot(X, imp[:,0], "b-",) 
    734     axes2 = axes1.twinx() 
    735      
    736     l2 = axes2.plot(X, imp[:,1], "g-",) 
    737     l3 = axes2.plot(X, imp[:,2], "r-",) 
    738      
    739     x_axis = axes1.xaxis 
    740     x_axis.set_ticks(X) 
    741     x_axis.set_ticklabels([a.name for a in attrs], rotation=90) 
    742      
    743     axes1.yaxis.set_label_text("nsubsets") 
    744     axes2.yaxis.set_label_text("normalized gcv or rss") 
    745  
    746     axes1.legend([l1, l2, l3], ["nsubsets", "gcv", "rss"]) 
    747     axes1.set_title("Variable importance") 
    748     fig.show() 
    749  
    750      
    751 def bagged_evimp(classifier, used_only=True): 
    752     """ Extract combined (average) evimp from an instance of BaggedClassifier 
    753      
    754     Example: :: 
    755         >>> from Orange.ensemble.bagging import BaggedLearner 
    756         >>> bc = BaggedLearner(EarthLearner(degree=3, terms=10), data) 
    757         >>> bagged_evimp(bc) 
    758          
    759     """ 
    760     def assert_type(object, class_): 
    761         if not isinstance(object, class_): 
    762             raise TypeError("Instance of %r expected." % (class_)) 
    763     from collections import defaultdict 
    764     from Orange.ensemble.bagging import BaggedClassifier 
    765      
    766     assert_type(classifier, BaggedClassifier) 
    767     bagged_imp = defaultdict(list) 
    768     attrs_by_name = defaultdict(list) 
    769     for c in classifier.classifiers: 
    770         assert_type(c, EarthClassifier) 
    771         imp = evimp(c, used_only=used_only) 
    772         for attr, score in imp: 
    773             bagged_imp[attr.name].append(score) # map by name 
    774             attrs_by_name[attr.name].append(attr) 
    775              
    776     for attr, scores in bagged_imp.items(): 
    777         scores = numpy.average(scores, axis=0) 
    778         bagged_imp[attr] = tuple(scores) 
    779      
    780      
    781     bagged_imp = sorted(bagged_imp.items(), key=lambda t: (t[1][0],t[1][1]), 
    782                         reverse=True) 
    783      
    784     bagged_imp = [(attrs_by_name[name][0], scores) for name, scores in bagged_imp] 
    785      
    786     if used_only: 
    787         bagged_imp = [(a, r) for a, r in bagged_imp if r[0] > 0] 
    788     return bagged_imp 
    789655 
    790656""" 
     
    859725             if d != 0] 
    860726    return " * ".join(knots) 
    861  
     727     
     728"""\ 
     729Variable importance estimation 
     730------------------------------ 
     731""" 
     732 
     733from collections import defaultdict 
     734 
     735def collect_source(vars): 
     736    """ Given a list of variables ``var``, return a mapping from source 
     737    variables (``source_variable`` or ``get_value_from.variable`` members) 
     738    back to the variables in ``vars`` (assumes the default preprocessor in 
     739    EarthLearner). 
     740     
     741    """ 
     742    source = defaultdict(list) 
     743    for var in vars: 
     744        svar = None 
     745        if var.source_variable: 
     746            source[var.source_variable].append(var) 
     747        elif isinstance(var.get_value_from, Orange.core.ClassifierFromVar): 
     748            source[var.get_value_from.variable].append(var) 
     749        elif isinstance(var.get_value_from, Orange.core.ImputeClassifier): 
     750            source[var.get_value_from.classifier_from_var.variable].append(var) 
     751        else: 
     752            source[var].append(var) 
     753    return dict(source) 
     754 
     755def map_to_source_var(var, sources): 
     756    """  
     757    """ 
     758    if var in sources: 
     759        return var 
     760    elif var.source_variable in sources: 
     761        return var.source_variable 
     762    elif isinstance(var.get_value_from, Orange.core.ClassifierFromVar): 
     763        return map_to_source_var(var.get_value_from.variable, sources) 
     764    elif isinstance(var.get_value_from, Orange.core.ImputeClassifier): 
     765        var = var.get_value_from.classifier_from_var.variable 
     766        return map_to_source_var(var, sources) 
     767    else: 
     768        return None 
     769     
     770def evimp(model, used_only=True): 
     771    """ Return the estimated variable importance for the model. 
     772     
     773    :param model: Earth model. 
     774    :type model: `EarthClassifier` 
     775     
     776    """ 
     777    if model.subsets is None: 
     778        raise ValueError("No subsets. Use the learner with 'prune=True'.") 
     779     
     780    subsets = model.subsets 
     781    n_subsets = numpy.sum(model.best_set) 
     782     
     783    rss = -numpy.diff(model.rss_per_subset) 
     784    gcv = -numpy.diff(model.gcv_per_subset) 
     785    attributes = list(model.domain.variables) 
     786     
     787    attr2ind = dict(zip(attributes, range(len(attributes)))) 
     788    importances = numpy.zeros((len(attributes), 4)) 
     789    importances[:, 0] = range(len(attributes)) 
     790     
     791    for i in range(1, n_subsets): 
     792        term_subset = subsets[i, :i + 1] 
     793        used_attributes = reduce(set.union, [model.used_attributes(term) \ 
     794                                             for term in term_subset], set()) 
     795        for attr in used_attributes: 
     796            importances[attr2ind[attr]][1] += 1.0 
     797            importances[attr2ind[attr]][2] += gcv[i - 1] 
     798            importances[attr2ind[attr]][3] += rss[i - 1] 
     799    imp_min = numpy.min(importances[:, [2, 3]], axis=0) 
     800    imp_max = numpy.max(importances[:, [2, 3]], axis=0) 
     801     
     802    #Normalize importances. 
     803    importances[:, [2, 3]] = 100.0 * (importances[:, [2, 3]] \ 
     804                            - [imp_min]) / ([imp_max - imp_min]) 
     805     
     806    importances = list(importances) 
     807    # Sort by n_subsets and gcv. 
     808    importances = sorted(importances, key=lambda row: (row[1], row[2]), 
     809                         reverse=True) 
     810    importances = numpy.array(importances) 
     811     
     812    if used_only: 
     813        importances = importances[importances[:,1] > 0.0] 
     814     
     815    res = [(attributes[int(row[0])], tuple(row[1:])) for row in importances] 
     816    return res 
     817 
     818 
     819def plot_evimp(evimp): 
     820    """ Plot the variable importances as returned from 
     821    :obj:`EarthClassifier.evimp` call. 
     822     
     823    :: 
     824        >>> data = Orange.data.Table("housing") 
     825        >>> c = EarthLearner(data, degree=3) 
     826        >>> plot_evimp(c.evimp()) 
     827         
     828    .. image:: files/earth-evimp.png 
     829      
     830    The left axis is the nsubsets measure an on the right are the normalized 
     831    RSS and GCV. 
     832     
     833    """ 
     834    from Orange.ensemble.bagging import BaggedClassifier 
     835    if isinstance(evimp, EarthClassifier): 
     836        evimp = evimp.evimp() 
     837    elif isinstance(evimp, BaggedClassifier): 
     838        evimp = bagged_evimp(evimp) 
     839         
     840    import pylab 
     841    fig = pylab.figure() 
     842    axes1 = fig.add_subplot(111) 
     843    attrs = [a for a, _ in evimp] 
     844    imp = [s for _, s in evimp] 
     845    imp = numpy.array(imp) 
     846    X = range(len(attrs)) 
     847    l1 = axes1.plot(X, imp[:,0], "b-",) 
     848    axes2 = axes1.twinx() 
     849     
     850    l2 = axes2.plot(X, imp[:,1], "g-",) 
     851    l3 = axes2.plot(X, imp[:,2], "r-",) 
     852     
     853    x_axis = axes1.xaxis 
     854    x_axis.set_ticks(X) 
     855    x_axis.set_ticklabels([a.name for a in attrs], rotation=90) 
     856     
     857    axes1.yaxis.set_label_text("nsubsets") 
     858    axes2.yaxis.set_label_text("normalized gcv or rss") 
     859 
     860    axes1.legend([l1, l2, l3], ["nsubsets", "gcv", "rss"]) 
     861    axes1.set_title("Variable importance") 
     862    fig.show() 
     863 
     864     
     865def bagged_evimp(classifier, used_only=True): 
     866    """ Extract combined (average) evimp from an instance of BaggedClassifier 
     867     
     868    Example: :: 
     869        >>> from Orange.ensemble.bagging import BaggedLearner 
     870        >>> bc = BaggedLearner(EarthLearner(degree=3, terms=10), data) 
     871        >>> bagged_evimp(bc) 
     872         
     873    """ 
     874    def assert_type(object, class_): 
     875        if not isinstance(object, class_): 
     876            raise TypeError("Instance of %r expected." % (class_)) 
     877    from collections import defaultdict 
     878    from Orange.ensemble.bagging import BaggedClassifier 
     879     
     880    assert_type(classifier, BaggedClassifier) 
     881    bagged_imp = defaultdict(list) 
     882    attrs_by_name = defaultdict(list) 
     883    for c in classifier.classifiers: 
     884        assert_type(c, EarthClassifier) 
     885        imp = evimp(c, used_only=used_only) 
     886        for attr, score in imp: 
     887            bagged_imp[attr.name].append(score) # map by name 
     888            attrs_by_name[attr.name].append(attr) 
     889             
     890    for attr, scores in bagged_imp.items(): 
     891        scores = numpy.average(scores, axis=0) 
     892        bagged_imp[attr] = tuple(scores) 
     893     
     894     
     895    bagged_imp = sorted(bagged_imp.items(), key=lambda t: (t[1][0],t[1][1]), 
     896                        reverse=True) 
     897     
     898    bagged_imp = [(attrs_by_name[name][0], scores) for name, scores in bagged_imp] 
     899     
     900    if used_only: 
     901        bagged_imp = [(a, r) for a, r in bagged_imp if r[0] > 0] 
     902    return bagged_imp 
    862903 
    863904""" 
     
    870911             
    871912class ScoreEarthImportance(scoring.Score): 
    872     """ Score features based on their importance in the Earth model using 
    873     ``bagged_evimp``'s function return value. 
     913    """ An :class:`Orange.feature.scoring.Score` subclass. 
     914    Scores features based on their importance in the Earth 
     915    model using ``bagged_evimp``'s function return value. 
     916     
    874917    """ 
    875918    # Return types   
     
    879922     
    880923    __new__ = _orange__new__(scoring.Score) 
     924    handles_discrete = True 
     925    handles_continuous = True 
     926    computes_thresholds = False 
    881927         
    882928    def __init__(self, t=10, degree=2, terms=10, score_what="nsubsets", cached=True): 
Note: See TracChangeset for help on using the changeset viewer.