Ignore:
Timestamp:
03/08/12 19:44:26 (2 years ago)
Author:
Matija Polajnar <matija.polajnar@…>
Branch:
default
Message:

Major refactorization of linear projections, fixing some bugs in the process.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • Orange/projection/linear.py

    r9916 r10475  
    1 ''' 
    2 ############################## 
    3 Linear projection (``linear``) 
    4 ############################## 
    5  
    6 .. index:: linear projection 
    7  
    8 .. index:: 
    9    single: projection; linear 
    10  
    11 This module contains the FreeViz algorithm 
    12 `(Demsar et al, 2005) <http://www.ailab.si/idamap/idamap2005/papers/12%20Demsar%20CR.pdf>`_ 
    13 [1], which finds a good two-dimensional projection of the given data, where the 
    14 quality is defined by a separation of the data from different classes and the 
    15 proximity of the instances from the same class. FreeViz would normally be used 
    16 through a widget since it is primarily a method for graphical exploration of 
    17 the data. About the only case where one would like to use this module directly 
    18 is to tests the classification aspects of the method, that is, to verify the 
    19 accuracy of the resulting kNN-like classifiers on a set of benchmark data sets. 
    20  
    21 Description of the method itself is far beyond the scope of this page. See the 
    22 above paper for the original version of the method; at the moment of writing 
    23 the method has been largely extended and not published yet, though the basic 
    24 principles are the same. 
    25  
    26 [1] Janez Demsar, Gregor Leban, Blaz Zupan: FreeViz - An Intelligent 
    27 Visualization Approach for Class-Labeled Multidimensional Data Sets, 
    28 Proceedings of IDAMAP 2005, Edinburgh.  
    29  
    30 *********************** 
    31 Projection Optimization 
    32 *********************** 
    33  
    34 .. autoclass:: Orange.projection.linear.FreeViz 
    35    :members: 
    36    :show-inheritance: 
    37    :exclude-members: attractG, attractG, autoSetParameters, cancelOptimization, 
    38       classPermutationList, classPermutationList, findProjection, 
    39       forceBalancing, forceSigma, getShownAttributeList, mirrorSymmetry, 
    40       optimizeSeparation, optimize_FAST_Separation, optimize_LDA_Separation, 
    41       optimize_SLOW_Separation, radialAnchors, randomAnchors, repelG, 
    42       s2nMixAnchors, s2nMixData, s2nPlaceAttributes, s2nSpread, 
    43       setStatusBarText, showAllAttributes, stepsBeforeUpdate, 
    44       useGeneralizedEigenvectors 
    45  
    46 ********************** 
    47 Learner and Classifier 
    48 ********************** 
    49  
    50 .. autoclass:: Orange.projection.linear.FreeVizLearner 
    51    :members: 
    52    :show-inheritance: 
    53  
    54 .. autoclass:: Orange.projection.linear.FreeVizClassifier 
    55    :members: 
    56    :show-inheritance: 
    57  
    58 .. autoclass:: Orange.projection.linear.S2NHeuristicLearner 
    59    :members: 
    60    :show-inheritance: 
    61  
    62 ''' 
    63  
     1#TODO: eliminate create_pls_projection (transform into a class) 
     2#TODO: Projector as a preprocessor 
    643 
    654import Orange 
     
    698import numpy 
    709 
    71 from numpy.linalg import inv, pinv, eig      # matrix inverse and eigenvectors 
    7210from Orange.preprocess.scaling import ScaleLinProjData 
    7311from Orange.orng import orngVisFuncts as visfuncts 
     
    11048    """ 
    11149    Contains an easy-to-use interface to the core of the method, which is 
    112     written in C++. 
     50    written in C++. Differs from other linear projection optimizers in that it itself can store the data 
     51    to make iterative optimization and visualization possible. It can, however, still be used as any other 
     52    projection optimizer by calling (:obj:`~Orange.projection.linear.FreeViz.__call__`) it. 
    11353     
    11454    .. attribute:: attract_g 
     
    184124                          1000] 
    185125 
     126    def __call__(self, dataset=None): 
     127        """ 
     128        Perform FreeViz optimization on the dataset, if given, and return a resulting 
     129        linear :class:`~Orange.projection.linear.Projector`. If no dataset is given, 
     130        the projection currently stored within the FreeViz object is returned as 
     131        a :class:`~Orange.projection.linear.Projector`. 
     132 
     133        :param dataset: input data set. 
     134        :type dataset: :class:`Orange.data.Table` 
     135 
     136        :rtype: :class:`~Orange.projection.linear.Projector` 
     137        """ 
     138        if dataset: 
     139            self.graph.setData(dataset) 
     140            self.show_all_attributes() 
     141 
     142            self.radial_anchors() 
     143            self.optimize_separation() 
     144 
     145            X = dataset.to_numpy_MA("a")[0] 
     146            Xm = numpy.mean(X, axis=0) 
     147            Xd = X - Xm 
     148            stdev = numpy.std(Xd, axis=0) 
     149        else: 
     150            Xm = numpy.zeros(len(self.graph.anchor_data)) 
     151            stdev = None 
     152 
     153        graph = self.graph 
     154 
     155        U = numpy.array([val[:2] for val in self.graph.anchor_data]).T 
     156 
     157        domain = graph.data_domain 
     158        if len(domain) > len(self.graph.anchor_data): 
     159            domain = Orange.data.Domain([graph.data_domain[a] 
     160                                         for _,_,a in self.graph.anchor_data], 
     161                graph.data_domain.class_var) 
     162 
     163        return Orange.projection.linear.Projector(input_domain = domain, 
     164            mean = Xm, 
     165            stdev = stdev, 
     166            standardize = False, 
     167            projection = U) 
     168 
     169 
    186170    def clear_data(self): 
    187171        self.s2n_mix_data = None 
     
    196180 
    197181    def show_all_attributes(self): 
    198         self.graph.anchorData = [(0,0, a.name) 
    199                                  for a in self.graph.dataDomain.attributes] 
     182        self.graph.anchor_data = [(0,0, a.name) 
     183                                 for a in self.graph.data_domain.attributes] 
    200184        self.radial_anchors() 
    201185         
     
    203187 
    204188    def get_shown_attribute_list(self): 
    205         return [anchor[2] for anchor in self.graph.anchorData] 
     189        return [anchor[2] for anchor in self.graph.anchor_data] 
    206190 
    207191    getShownAttributeList = get_shown_attribute_list 
     
    216200        if not attr_list: 
    217201            return 
    218         if "3d" in self.parentName.lower(): 
     202        if hasattr(self, "parentName") and "3d" in self.parentName.lower(): 
    219203            self.graph.anchor_data = self.graph.create_anchors(len(attr_list), attr_list) 
    220204            return 
    221205        phi = 2*math.pi/len(attr_list) 
    222         self.graph.anchorData = [(math.cos(i*phi), math.sin(i*phi), a) 
     206        self.graph.anchor_data = [(math.cos(i*phi), math.sin(i*phi), a) 
    223207                                 for i, a in enumerate(attr_list)] 
    224208 
     
    230214         
    231215        """ 
    232         if not self.graph.haveData: 
     216        if not self.graph.have_data: 
    233217            return 
    234218        attr_list = self.get_shown_attribute_list() 
     
    269253                anchors = [(x[0]/maxdist, x[1]/maxdist, x[2]/maxdist, x[3]) for x in anchors] 
    270254 
    271             self.graph.anchorData = anchors 
     255            self.graph.anchor_data = anchors 
    272256            return 
    273257 
     
    299283            pass 
    300284 
    301         self.graph.anchorData = anchors 
     285        self.graph.anchor_data = anchors 
    302286 
    303287    randomAnchors = random_anchors 
     
    319303        """ 
    320304        # check if we have data and a discrete class 
    321         if (not self.graph.haveData or len(self.graph.rawData) == 0 
    322             or not (self.graph.dataHasClass or distances)): 
     305        if (not self.graph.have_data or len(self.graph.raw_data) == 0 
     306            or not (self.graph.data_has_class or distances)): 
    323307            return 
    324         ai = self.graph.attributeNameIndex 
     308        ai = self.graph.attribute_name_index 
    325309        attr_indices = [ai[label] for label in self.get_shown_attribute_list()] 
    326310        if not attr_indices: return 
     
    352336                    if self.__class__ != FreeViz and self.cancel_optimization == 1: 
    353337                        return 
    354                     self.graph.anchorData, (xanchors, yanchors, zanchors) = impl(attr_indices, 
    355                                                                                  self.graph.anchorData, 
     338                    self.graph.anchor_data, (xanchors, yanchors, zanchors) = impl(attr_indices, 
     339                                                                                 self.graph.anchor_data, 
    356340                                                                                 xanchors, 
    357341                                                                                 yanchors, 
     
    364348                    if self.__class__ != FreeViz and self.cancel_optimization == 1: 
    365349                        return 
    366                     self.graph.anchorData, (xanchors, yanchors) = impl(attr_indices, 
    367                                                                        self.graph.anchorData, 
     350                    self.graph.anchor_data, (xanchors, yanchors) = impl(attr_indices, 
     351                                                                       self.graph.anchor_data, 
    368352                                                                       xanchors, 
    369353                                                                       yanchors) 
     
    377361        optimizer = [orangeom.optimizeAnchors, orangeom.optimizeAnchorsRadial, 
    378362                     orangeom.optimizeAnchorsR][self.restrain] 
    379         ai = self.graph.attributeNameIndex 
     363        ai = self.graph.attribute_name_index 
    380364        attr_indices = [ai[label] for label in self.get_shown_attribute_list()] 
    381365        if not attr_indices: return 
    382366 
    383367        # repeat until less than 1% energy decrease in 5 consecutive iterations*steps steps 
    384         positions = [numpy.array([x[:2] for x in self.graph.anchorData])] 
     368        positions = [numpy.array([x[:2] for x in self.graph.anchor_data])] 
    385369        needed_steps = 0 
    386370 
    387         valid_data = self.graph.getValidList(attr_indices) 
     371        valid_data = self.graph.get_valid_list(attr_indices) 
    388372        n_valid = sum(valid_data)  
    389373        if not n_valid: 
    390374            return 0 
    391375 
    392         data = numpy.compress(valid_data, self.graph.noJitteringScaledData, 
     376        data = numpy.compress(valid_data, self.graph.no_jittering_scaled_data, 
    393377                              axis=1) 
    394378        data = numpy.transpose(data).tolist() 
     
    412396        else: 
    413397            classes = numpy.compress(valid_data, 
    414                                      self.graph.originalData[self.graph.dataClassIndex]).tolist() 
     398                                     self.graph.original_data[self.graph.data_class_index]).tolist() 
    415399        while 1: 
    416             self.graph.anchorData = optimizer(data, classes, 
    417                                               self.graph.anchorData, 
     400            self.graph.anchor_data = optimizer(data, classes, 
     401                                              self.graph.anchor_data, 
    418402                                              attr_indices, 
    419403                                              attractG = self.attract_g, 
     
    423407                                              dynamicBalancing = self.force_balancing, 
    424408                                              steps = steps, 
    425                                               normalizeExamples = self.graph.normalizeExamples, 
     409                                              normalizeExamples = self.graph.normalize_examples, 
    426410                                              contClass = 2 if distances 
    427                                               else self.graph.dataHasContinuousClass, 
     411                                              else self.graph.data_has_continuous_class, 
    428412                                              mirrorSymmetry = self.mirror_symmetry) 
    429413            needed_steps += steps 
     
    433417 
    434418            if hasattr(self.graph, "updateData"): 
    435                 self.graph.potentialsBmp = None 
     419                self.graph.potentials_emp = None 
    436420                self.graph.updateData() 
    437421 
    438422            positions = positions[-49:]+[numpy.array([x[:2] for x 
    439                                                       in self.graph.anchorData])] 
     423                                                      in self.graph.anchor_data])] 
    440424            if len(positions)==50: 
    441425                m = max(numpy.sum((positions[0]-positions[49])**2), 0) 
     
    453437                          "YAnchors": "yanchors"}) 
    454438    def optimize_lda_separation(self, attr_indices, anchor_data, xanchors = None, yanchors = None): 
    455         if (not self.graph.haveData or len(self.graph.rawData) == 0 
    456             or not self.graph.dataHasDiscreteClass):  
     439        if (not self.graph.have_data or len(self.graph.raw_data) == 0 
     440            or not self.graph.data_has_discrete_class):  
    457441            return anchor_data, (xanchors, yanchors) 
    458         class_count = len(self.graph.dataDomain.classVar.values) 
    459         valid_data = self.graph.getValidList(attr_indices) 
     442        class_count = len(self.graph.data_domain.classVar.values) 
     443        valid_data = self.graph.get_valid_list(attr_indices) 
    460444        selected_data = numpy.compress(valid_data, 
    461                                        numpy.take(self.graph.noJitteringScaledData, 
     445                                       numpy.take(self.graph.no_jittering_scaled_data, 
    462446                                                  attr_indices, axis = 0), 
    463447                                       axis = 1) 
     
    468452            yanchors = numpy.array([a[1] for a in anchor_data], numpy.float) 
    469453 
    470         trans_proj_data = self.graph.createProjectionAsNumericArray(attr_indices, 
    471                                                                     valid_data = valid_data, 
     454        trans_proj_data = self.graph.create_projection_as_numeric_array(attr_indices, 
     455                                                                    validData = valid_data, 
    472456                                                                    xanchors = xanchors, 
    473457                                                                    yanchors = yanchors, 
    474                                                                     scaleFactor = self.graph.scaleFactor, 
    475                                                                     normalize = self.graph.normalizeExamples, 
     458                                                                    scaleFactor = self.graph.scale_factor, 
     459                                                                    normalize = self.graph.normalize_examples, 
    476460                                                                    useAnchorData = 1) 
    477461        if trans_proj_data == None: 
     
    580564                          "YAnchors": "yanchors"}) 
    581565    def optimize_slow_separation(self, attr_indices, anchor_data, xanchors = None, yanchors = None): 
    582         if (not self.graph.haveData or len(self.graph.rawData) == 0 
    583             or not self.graph.dataHasDiscreteClass):  
     566        if (not self.graph.have_data or len(self.graph.raw_data) == 0 
     567            or not self.graph.data_has_discrete_class):  
    584568            return anchor_data, (xanchors, yanchors) 
    585         valid_data = self.graph.getValidList(attr_indices) 
    586         selected_data = numpy.compress(valid_data, numpy.take(self.graph.noJitteringScaledData, 
     569        valid_data = self.graph.get_valid_list(attr_indices) 
     570        selected_data = numpy.compress(valid_data, numpy.take(self.graph.no_jittering_scaled_data, 
    587571                                                              attr_indices, 
    588572                                                              axis = 0), 
     
    594578            yanchors = numpy.array([a[1] for a in anchor_data], numpy.float) 
    595579 
    596         trans_proj_data = self.graph.createProjectionAsNumericArray(attr_indices, 
    597                                                                     valid_data = valid_data, 
     580        trans_proj_data = self.graph.create_projection_as_numeric_array(attr_indices, 
     581                                                                    validData = valid_data, 
    598582                                                                    xanchors = xanchors, 
    599583                                                                    yanchors = yanchors, 
    600                                                                     scaleFactor = self.graph.scaleFactor, 
    601                                                                     normalize = self.graph.normalizeExamples, 
     584                                                                    scaleFactor = self.graph.scale_factor, 
     585                                                                    normalize = self.graph.normalize_examples, 
    602586                                                                    useAnchorData = 1) 
    603587        if trans_proj_data == None: 
     
    660644                          "YAnchors": "yanchors"}) 
    661645    def optimize_lda_separation_3D(self, attr_indices, anchor_data, xanchors = None, yanchors = None, zanchors = None): 
    662         if (not self.graph.haveData or len(self.graph.rawData) == 0 
    663             or not self.graph.dataHasDiscreteClass):  
     646        if (not self.graph.have_data or len(self.graph.raw_data) == 0 
     647            or not self.graph.data_has_discrete_class):  
    664648            return anchor_data, (xanchors, yanchors, zanchors) 
    665         class_count = len(self.graph.dataDomain.classVar.values) 
    666         valid_data = self.graph.getValidList(attr_indices) 
     649        class_count = len(self.graph.data_domain.classVar.values) 
     650        valid_data = self.graph.get_valid_list(attr_indices) 
    667651        selected_data = numpy.compress(valid_data, 
    668                                        numpy.take(self.graph.noJitteringScaledData, 
     652                                       numpy.take(self.graph.no_jittering_scaled_data, 
    669653                                                  attr_indices, axis = 0), 
    670654                                       axis = 1) 
     
    677661            zanchors = numpy.array([a[2] for a in anchor_data], numpy.float) 
    678662 
    679         trans_proj_data = self.graph.createProjectionAsNumericArray(attr_indices, 
    680                                                                     valid_data = valid_data, 
     663        trans_proj_data = self.graph.create_projection_as_numeric_array(attr_indices, 
     664                                                                    validData = valid_data, 
    681665                                                                    xanchors = xanchors, 
    682666                                                                    yanchors = yanchors, 
    683667                                                                    zanchors = zanchors, 
    684                                                                     scaleFactor = self.graph.scaleFactor, 
    685                                                                     normalize = self.graph.normalizeExamples, 
     668                                                                    scaleFactor = self.graph.scale_factor, 
     669                                                                    normalize = self.graph.normalize_examples, 
    686670                                                                    useAnchorData = 1) 
    687671        if trans_proj_data == None: 
     
    796780                          "YAnchors": "yanchors"}) 
    797781    def optimize_slow_separation_3D(self, attr_indices, anchor_data, xanchors = None, yanchors = None, zanchors = None): 
    798         if (not self.graph.haveData or len(self.graph.rawData) == 0 
    799             or not self.graph.dataHasDiscreteClass):  
     782        if (not self.graph.have_data or len(self.graph.raw_data) == 0 
     783            or not self.graph.data_has_discrete_class):  
    800784            return anchor_data, (xanchors, yanchors, zanchors) 
    801         valid_data = self.graph.getValidList(attr_indices) 
    802         selected_data = numpy.compress(valid_data, numpy.take(self.graph.noJitteringScaledData, 
     785        valid_data = self.graph.get_valid_list(attr_indices) 
     786        selected_data = numpy.compress(valid_data, numpy.take(self.graph.no_jittering_scaled_data, 
    803787                                                              attr_indices, 
    804788                                                              axis = 0), 
     
    812796            zanchors = numpy.array([a[2] for a in anchor_data], numpy.float) 
    813797 
    814         trans_proj_data = self.graph.createProjectionAsNumericArray(attr_indices, 
    815                                                                     valid_data = valid_data, 
     798        trans_proj_data = self.graph.create_projection_as_numeric_array(attr_indices, 
     799                                                                    validData = valid_data, 
    816800                                                                    XAnchors = xanchors, 
    817801                                                                    YAnchors = yanchors, 
    818802                                                                    ZAnchors = zanchors, 
    819                                                                     scaleFactor = self.graph.scaleFactor, 
    820                                                                     normalize = self.graph.normalizeExamples, 
     803                                                                    scaleFactor = self.graph.scale_factor, 
     804                                                                    normalize = self.graph.normalize_examples, 
    821805                                                                    useAnchorData = 1) 
    822806        if trans_proj_data == None: 
     
    898882    def s2n_mix_anchors(self, set_attribute_list_in_radviz = 1): 
    899883        # check if we have data and a discrete class 
    900         if (not self.graph.haveData or len(self.graph.rawData) == 0 
    901             or not self.graph.dataHasDiscreteClass):  
     884        if (not self.graph.have_data or len(self.graph.raw_data) == 0 
     885            or not self.graph.data_has_discrete_class):  
    902886            self.set_statusbar_text("S2N only works on data with a discrete class value") 
    903887            return 
     
    905889        # compute the quality of attributes only once 
    906890        if self.s2n_mix_data == None: 
    907             ranked_attrs, ranked_attrs_by_class = visfuncts.findAttributeGroupsForRadviz(self.graph.rawData, 
     891            ranked_attrs, ranked_attrs_by_class = visfuncts.findAttributeGroupsForRadviz(self.graph.raw_data, 
    908892                                                                                         visfuncts.S2NMeasureMix()) 
    909893            self.s2n_mix_data = (ranked_attrs, ranked_attrs_by_class) 
     
    939923 
    940924        anchor_data = anchor_data[(len(attrs)/(2*class_count)):] + anchor_data[:(len(attrs)/(2*class_count))] 
    941         self.graph.anchorData = anchor_data 
     925        self.graph.anchor_data = anchor_data 
    942926        attrNames = [anchor[2] for anchor in anchor_data] 
    943927 
     
    956940                          "percentDataUsed": "percent_data_used"}) 
    957941    def find_projection(self, method, attr_indices = None, set_anchors = 0, percent_data_used = 100): 
    958         if not self.graph.haveData: return 
    959         ai = self.graph.attributeNameIndex 
     942        if not self.graph.have_data: return 
     943        ai = self.graph.attribute_name_index 
    960944        if attr_indices == None: 
    961945            attributes = self.get_shown_attribute_list() 
     
    963947        if len(attr_indices) == 0: return None 
    964948 
    965         valid_data = self.graph.getValidList(attr_indices) 
     949        valid_data = self.graph.get_valid_list(attr_indices) 
    966950        if sum(valid_data) == 0: return None 
    967951 
    968         data_matrix = numpy.compress(valid_data, numpy.take(self.graph.noJitteringScaledData, 
     952        data_matrix = numpy.compress(valid_data, numpy.take(self.graph.no_jittering_scaled_data, 
    969953                                                            attr_indices, 
    970954                                                            axis = 0), 
    971955                                     axis = 1) 
    972         if self.graph.dataHasClass: 
     956        if self.graph.data_has_class: 
    973957            class_array = numpy.compress(valid_data, 
    974                                          self.graph.noJitteringScaledData[self.graph.dataClassIndex]) 
     958                                         self.graph.no_jittering_scaled_data[self.graph.data_class_index]) 
    975959 
    976960        if percent_data_used != 100: 
    977             indices = Orange.data.sample.SubsetIndices2(self.graph.rawData, 
     961            indices = Orange.data.sample.SubsetIndices2(self.graph.raw_data, 
    978962                                                1.0-(float(percent_data_used)/100.0)) 
    979963            try: 
     
    981965            except: 
    982966                pass 
    983             if self.graph.dataHasClass: 
     967            if self.graph.data_has_class: 
    984968                class_array = numpy.compress(indices, class_array) 
    985969 
     
    987971        vectors = None 
    988972        if method == DR_PCA: 
    989             vals, vectors = create_pca_projection(data_matrix, ncomps = ncomps, 
    990                                                   use_generalized_eigenvectors = self.use_generalized_eigenvectors) 
    991         elif method == DR_SPCA and self.graph.dataHasClass: 
    992             vals, vectors = create_pca_projection(data_matrix, class_array, 
    993                                                   ncomps = ncomps, 
    994                                                   use_generalized_eigenvectors = self.use_generalized_eigenvectors) 
    995         elif method == DR_PLS and self.graph.dataHasClass: 
     973            pca = Pca(standardize=False, max_components=ncomps, 
     974                use_generalized_eigenvectors=0) 
     975            domain = Orange.data.Domain([Orange.feature.Continuous("g%d"%i) for i 
     976                                         in xrange(len(data_matrix))], False) 
     977            pca = pca(Orange.data.Table(domain, data_matrix.T)) 
     978            vals, vectors = pca.eigen_values, pca.projection 
     979        elif method == DR_SPCA and self.graph.data_has_class: 
     980            pca = Spca(standardize=False, max_components=ncomps, 
     981                use_generalized_eigenvectors=self.use_generalized_eigenvectors) 
     982            domain = Orange.data.Domain([Orange.feature.Continuous("g%d"%i) for i 
     983                                         in xrange(len(data_matrix))], Orange.feature.Continuous("c")) 
     984            pca = pca(Orange.data.Table(domain, 
     985                numpy.hstack([data_matrix.T, numpy.array(class_array, ndmin=2).T]))) 
     986            vals, vectors = pca.eigen_values, pca.projection 
     987        elif method == DR_PLS and self.graph.data_has_class: 
    996988            data_matrix = data_matrix.transpose() 
    997989            class_matrix = numpy.transpose(numpy.matrix(class_array)) 
     
    10171009        xanchors /= m 
    10181010        yanchors /= m 
    1019         names = self.graph.attributeNames 
     1011        names = self.graph.attribute_names 
    10201012        attributes = [names[attr_indices[i]] for i in range(len(attr_indices))] 
    10211013 
    10221014        if set_anchors: 
    10231015            if ncomps == 3: 
    1024                 self.graph.setAnchors(list(xanchors), list(yanchors), list(zanchors), attributes) 
     1016                self.graph.set_anchors(list(xanchors), list(yanchors), list(zanchors), attributes) 
    10251017            else: 
    1026                 self.graph.setAnchors(list(xanchors), list(yanchors), attributes) 
    1027             self.graph.updateData() 
    1028             self.graph.repaint() 
     1018                self.graph.set_anchors(list(xanchors), list(yanchors), attributes) 
     1019            if hasattr(self.graph, "updateData"): 
     1020                self.graph.updateData() 
     1021            if hasattr(self.graph, "repaint"): 
     1022                self.graph.repaint() 
    10291023 
    10301024        if ncomps == 3: 
     
    11131107createPLSProjection = create_pls_projection 
    11141108 
    1115 # if no class data is provided we create PCA projection 
    1116 # if there is class data then create SPCA projection 
     1109# ############################################################################# 
     1110# class that represents freeviz classifier 
     1111class FreeVizClassifier(Orange.classification.Classifier): 
     1112    """ 
     1113    A kNN classifier on the 2D projection of the data, optimized by FreeViz. 
     1114     
     1115    Usually the learner 
     1116    (:class:`Orange.projection.linear.FreeVizLearner`) is used to construct the 
     1117    classifier. 
     1118     
     1119    When constructing the classifier manually, the following parameters can 
     1120    be passed: 
     1121     
     1122    :param data: table of data instances to project to a 2D plane and use for 
     1123        classification. 
     1124    :type data: :class:`Orange.data.Table` 
     1125     
     1126    :param freeviz: the FreeViz algorithm instance to use to optimize the 2D 
     1127        projection. 
     1128    :type freeviz: :class:`Orange.projection.linear.FreeViz` 
     1129     
     1130    """ 
     1131     
     1132    def __init__(self, data, freeviz): 
     1133        self.freeviz = freeviz 
     1134 
     1135        if self.freeviz.__class__ != FreeViz: 
     1136            self.freeviz.parentWidget.setData(data) 
     1137            self.freeviz.parentWidget.showAllAttributes = 1 
     1138        else: 
     1139            self.freeviz.graph.set_data(data) 
     1140            self.freeviz.show_all_attributes() 
     1141 
     1142        #self.FreeViz.randomAnchors() 
     1143        self.freeviz.radial_anchors() 
     1144        self.freeviz.optimize_separation() 
     1145 
     1146        graph = self.freeviz.graph 
     1147        ai = graph.attribute_name_index 
     1148        labels = [a[2] for a in graph.anchor_data] 
     1149        indices = [ai[label] for label in labels] 
     1150 
     1151        valid_data = graph.get_valid_list(indices) 
     1152        domain = Orange.data.Domain([graph.data_domain[i].name for i in indices]+ 
     1153                               [graph.data_domain.classVar.name], 
     1154                               graph.data_domain) 
     1155        offsets = [graph.attr_values[graph.attribute_names[i]][0] 
     1156                   for i in indices] 
     1157        normalizers = [graph.get_min_max_val(i) for i in indices] 
     1158        selected_data = numpy.take(graph.original_data, indices, axis = 0) 
     1159        averages = numpy.average(numpy.compress(valid_data, selected_data, 
     1160                                                axis=1), 1) 
     1161        class_data = numpy.compress(valid_data, 
     1162                                    graph.original_data[graph.data_class_index]) 
     1163 
     1164        graph.create_projection_as_numeric_array(indices, use_anchor_data = 1, 
     1165                                             remove_missing_data = 0, 
     1166                                             valid_data = valid_data, 
     1167                                             jitter_size = -1) 
     1168        self.classifier = Orange.classification.knn.P2NN(domain, 
     1169                                      numpy.transpose(numpy.array([numpy.compress(valid_data, 
     1170                                                                                  graph.unscaled_x_positions), 
     1171                                                                   numpy.compress(valid_data, 
     1172                                                                                  graph.unscaled_y_positions), 
     1173                                                                   class_data])), 
     1174                                      graph.anchor_data, offsets, normalizers, 
     1175                                      averages, graph.normalize_examples, law=1) 
     1176 
     1177    # for a given instance run argumentation and find out to which class it most often fall 
     1178    @deprecated_keywords({"example": "instance", "returnType": "return_type"}) 
     1179    def __call__(self, instance, return_type=Orange.classification.Classifier.GetValue): 
     1180        #instance.setclass(0) 
     1181        return self.classifier(instance, return_type) 
     1182 
     1183FreeVizClassifier = deprecated_members({"FreeViz":"freeviz"})(FreeVizClassifier) 
     1184 
     1185class FreeVizLearner(Orange.classification.Learner): 
     1186    """ 
     1187    A learner that builds a :class:`FreeVizClassifier` on given data. An 
     1188    instance of :class:`FreeViz` can be passed to the constructor as a 
     1189    keyword argument :obj:`freeviz`.     
     1190 
     1191    If data instances are provided to the constructor, the learning algorithm 
     1192    is called and the resulting classifier is returned instead of the learner. 
     1193     
     1194    """ 
     1195    def __new__(cls, freeviz = None, instances = None, weight_id = 0, **argkw): 
     1196        self = Orange.classification.Learner.__new__(cls, **argkw) 
     1197        if instances: 
     1198            self.__init__(freeviz, **argkw) 
     1199            return self.__call__(instances, weight_id) 
     1200        else: 
     1201            return self 
     1202 
     1203    def __init__(self, freeviz = None): 
     1204        if not freeviz: 
     1205            freeviz = FreeViz() 
     1206        self.freeviz = freeviz 
     1207        self.name = "freeviz Learner" 
     1208 
     1209    @deprecated_keywords({"examples": "instances", "weightID": "weight_id"}) 
     1210    def __call__(self, instances, weight_id = 0): 
     1211        return FreeVizClassifier(instances, self.freeviz) 
     1212 
     1213FreeVizLearner = deprecated_members({"FreeViz":"freeviz"})(FreeVizLearner) 
     1214 
     1215 
     1216class S2NHeuristicLearner(Orange.classification.Learner): 
     1217    """ 
     1218    This class is not documented yet. 
     1219     
     1220    """ 
     1221    def __new__(cls, freeviz = None, instances = None, weight_id = 0, **argkw): 
     1222        self = Orange.classification.Learner.__new__(cls, **argkw) 
     1223        if instances: 
     1224            self.__init__(freeviz, **argkw) 
     1225            return self.__call__(instances, weight_id) 
     1226        else: 
     1227            return self 
     1228 
     1229    def __init__(self, freeviz = None): 
     1230        if not freeviz: 
     1231            freeviz = FreeViz() 
     1232        self.freeviz = freeviz 
     1233        self.name = "S2N Feature Selection Learner" 
     1234 
     1235    @deprecated_keywords({"examples": "instances", "weightID": "weight_id"}) 
     1236    def __call__(self, instances, weight_id = 0): 
     1237        return S2NHeuristicClassifier(instances, self.freeviz) 
     1238 
     1239S2NHeuristicLearner = deprecated_members({"FreeViz": 
     1240                                          "freeviz"})(S2NHeuristicLearner) 
     1241 
     1242class Projector(object): 
     1243    """ 
     1244    Stores a linear projection of data and uses it to transform any given data with matching input domain. 
     1245 
     1246    .. attribute:: input_domain 
     1247 
     1248        Domain of the data set that was used to construct principal component 
     1249        subspace. 
     1250 
     1251    .. attribute:: output_domain 
     1252 
     1253        Domain used in returned data sets. This domain has a continuous 
     1254        variable for each axis in the projected space, 
     1255        and no class variable(s). 
     1256 
     1257    .. attribute:: mean 
     1258 
     1259        Array containing means of each variable in the data set that was used 
     1260        to construct the projection. 
     1261 
     1262    .. attribute:: stdev 
     1263 
     1264        An array containing standard deviations of each variable in the data 
     1265        set that was used to construct the projection. 
     1266 
     1267    .. attribute:: standardize 
     1268 
     1269        True, if standardization was used when constructing the projection. If 
     1270        set, instances will be standardized before being projected. 
     1271 
     1272    .. attribute:: projection 
     1273 
     1274        Array containing projection (vectors that describe the 
     1275        transformation from input to output domain). 
     1276 
     1277    """ 
     1278    def __init__(self, **kwds): 
     1279        self.__dict__.update(kwds) 
     1280        if not hasattr(self, "output_domain"): 
     1281            self.output_domain = Orange.data.Domain([Orange.feature.Continuous("a.%d"%(i+1)) for i in range(len(self.projection))], False) 
     1282 
     1283 
     1284    def __call__(self, data): 
     1285        """ 
     1286        Project data. 
     1287 
     1288        :param data: input data set 
     1289        :type data: :class:`Orange.data.Table` 
     1290 
     1291        :rtype: :class:`Orange.data.Table` 
     1292        """ 
     1293        if type(data) != Orange.data.Table: 
     1294            data = Orange.data.Table([data]) 
     1295        if len(self.projection.T) != len(data.domain.features): 
     1296            data = Orange.data.Table(self.input_domain, data) 
     1297 
     1298        X = data.to_numpy_MA("a")[0] 
     1299        Xm, U = self.mean, self.projection 
     1300        n, m = X.shape 
     1301 
     1302        if m != len(self.projection.T): 
     1303            raise Orange.core.KernelException, "Invalid number of features" 
     1304 
     1305        Xd = X - Xm 
     1306 
     1307        if self.standardize: 
     1308            Xd /= self.stdev 
     1309 
     1310        self.A = numpy.ma.dot(Xd, U.T) 
     1311 
     1312        return Orange.data.Table(self.output_domain, self.A.tolist()) 
     1313 
     1314#color table for biplot 
     1315Colors = ['bo','go','yo','co','mo'] 
     1316 
     1317class Pca(object): 
     1318    """ 
     1319    Orthogonal transformation of data into a set of uncorrelated variables called 
     1320    principal components. This transformation is defined in such a way that the 
     1321    first variable has as high variance as possible. 
     1322 
     1323    If data instances are provided to the constructor, 
     1324    the optimization algorithm is called and the resulting projector 
     1325    (:class:`~Orange.projection.linear.PcaProjector`) is 
     1326    returned instead of the optimizer (instance of this class). 
     1327 
     1328    :param standardize: perform standardization of the data set. 
     1329    :type standardize: boolean 
     1330    :param max_components: maximum number of retained components. 
     1331    :type max_components: int 
     1332    :param variance_covered: percent of the variance to cover with components. 
     1333    :type variance_covered: float 
     1334    :param use_generalized_eigenvectors: use generalized eigenvectors (ie. 
     1335        multiply data matrix with inverse of its covariance matrix). 
     1336    :type use_generalized_eigenvectors: boolean 
     1337 
     1338    :rtype: :class:`~Orange.projection.linear.Pca` or 
     1339            :class:`~Orange.projection.linear.PcaProjector` 
     1340    """ 
     1341 
     1342    def __new__(cls, dataset = None, **kwds): 
     1343        optimizer = object.__new__(cls) 
     1344        optimizer.__init__(**kwds) 
     1345 
     1346        if dataset: 
     1347            return optimizer(dataset) 
     1348        else: 
     1349            return optimizer 
     1350 
     1351    def __init__(self, standardize = True, 
     1352                 max_components = 0, variance_covered = 1, 
     1353                 use_generalized_eigenvectors = 0): 
     1354        self.standardize = standardize 
     1355        self.max_components = max_components 
     1356        self.variance_covered = variance_covered if variance_covered < 1. else 1 
     1357        self.use_generalized_eigenvectors = use_generalized_eigenvectors 
     1358 
     1359    def _pca(self, dataset, Xd, Xg): 
     1360        n,m = Xd.shape 
     1361        if n < m: 
     1362            C = numpy.ma.dot(Xg.T, Xd.T) 
     1363            V, D, T = numpy.linalg.svd(C) 
     1364            U = numpy.ma.dot(V.T, Xd) / numpy.sqrt(D.reshape(-1,1)) 
     1365        else: 
     1366            C = numpy.ma.dot(Xg, Xd) 
     1367            U, D, T = numpy.linalg.svd(C) 
     1368 
     1369        U = U.T  # eigenvectors are now in rows 
     1370        return U, D 
     1371 
     1372    def __call__(self, dataset): 
     1373        """ 
     1374        Perform a PCA analysis on a data set and return a linear projector 
     1375        that maps data into principal component subspace. 
     1376 
     1377        :param dataset: input data set. 
     1378        :type dataset: :class:`Orange.data.Table` 
     1379 
     1380        :rtype: :class:`~Orange.projection.linear.PcaProjector` 
     1381        """ 
     1382 
     1383        X = dataset.to_numpy_MA("a")[0] 
     1384        N,M = X.shape 
     1385        Xm = numpy.mean(X, axis=0) 
     1386        Xd = X - Xm 
     1387 
     1388        #take care of the constant features 
     1389        stdev = numpy.std(Xd, axis=0) 
     1390        relevant_features = stdev != 0 
     1391        if self.standardize: 
     1392            stdev[stdev == 0] = 1. 
     1393            Xd /= stdev 
     1394        Xd = Xd[:,relevant_features] 
     1395 
     1396        #use generalized eigenvectors 
     1397        if self.use_generalized_eigenvectors: 
     1398            inv_covar = numpy.linalg.inv(numpy.dot(Xd.T, Xd)) 
     1399            Xg = numpy.dot(inv_covar, Xd.T) 
     1400        else: 
     1401            Xg = Xd.T 
     1402 
     1403        #actual pca 
     1404        n,m = Xd.shape 
     1405        U, D = self._pca(dataset, Xd, Xg) 
     1406 
     1407        #insert zeros for constant features 
     1408        n, m = U.shape 
     1409        if m != M: 
     1410            U_ = numpy.zeros((n,M)) 
     1411            U_[:,relevant_features] = U 
     1412            U = U_ 
     1413 
     1414        variance_sum = D.sum() 
     1415 
     1416        #select eigen vectors 
     1417        if self.variance_covered != 1: 
     1418            nfeatures = numpy.nonzero(numpy.cumsum(D) / sum(D) >= self.variance_covered)[0][0] + 1 
     1419            U = U[:nfeatures, :] 
     1420            D = D[:nfeatures] 
     1421 
     1422        if self.max_components > 0: 
     1423            U = U[:self.max_components, :] 
     1424            D = D[:self.max_components] 
     1425 
     1426        n, m = U.shape 
     1427        pc_domain = Orange.data.Domain([Orange.feature.Continuous("Comp.%d"% 
     1428                                                                  (i+1)) for i in range(n)], False) 
     1429 
     1430        return PcaProjector(input_domain = dataset.domain, 
     1431            output_domain = pc_domain, 
     1432            pc_domain = pc_domain, 
     1433            mean = Xm, 
     1434            stdev = stdev, 
     1435            standardize = self.standardize, 
     1436            eigen_vectors = U, 
     1437            projection = U, 
     1438            eigen_values = D, 
     1439            variance_sum = variance_sum) 
     1440 
     1441 
     1442class Spca(Pca): 
     1443    def _pca(self, dataset, Xd, Xg): 
     1444        # define the Laplacian matrix 
     1445        c = dataset.to_numpy("c")[0] 
     1446        l = -numpy.array(numpy.hstack( [(c != v) for v in c]), dtype='f') 
     1447        l -= numpy.diagflat(numpy.sum(l, axis=0)) 
     1448 
     1449        Xg = numpy.dot(Xg, l) 
     1450 
     1451        return Pca._pca(self, dataset, Xd, Xg) 
     1452 
     1453class PcaProjector(Projector): 
     1454    """ 
     1455    .. attribute:: pc_domain 
     1456 
     1457        Synonymous for :obj:`~Orange.projection.linear.Projector.output_domain`. 
     1458 
     1459    .. attribute:: eigen_vectors 
     1460 
     1461        Synonymous for :obj:`~Orange.projection.linear.Projector.projection`. 
     1462 
     1463    .. attribute:: eigen_values 
     1464 
     1465        Array containing standard deviations of principal components. 
     1466 
     1467    .. attribute:: variance_sum 
     1468 
     1469        Sum of all variances in the data set that was used to construct the PCA 
     1470        space. 
     1471 
     1472    """ 
     1473 
     1474    def __init__(self, **kwds): 
     1475        self.__dict__.update(kwds) 
     1476 
     1477    def __str__(self): 
     1478        ncomponents = 10 
     1479        s = self.variance_sum 
     1480        cs = numpy.cumsum(self.eigen_values) / s 
     1481        return "\n".join([ 
     1482            "PCA SUMMARY", 
     1483            "", 
     1484            "Std. deviation of components:", 
     1485            " ".join(["              "] + 
     1486                     ["%10s" % a.name for a in self.pc_domain.attributes]), 
     1487            " ".join(["Std. deviation"] + 
     1488                     ["%10.3f" % a for a in self.eigen_values]), 
     1489            " ".join(["Proportion Var"] + 
     1490                     ["%10.3f" % a for a in  self.eigen_values / s * 100]), 
     1491            " ".join(["Cumulative Var"] + 
     1492                     ["%10.3f" % a for a in cs * 100]), 
     1493            "", 
     1494            #"Loadings:", 
     1495            #" ".join(["%10s"%""] + ["%10s" % a.name for a in self.pc_domain]), 
     1496            #"\n".join([ 
     1497            #    " ".join([a.name] + ["%10.3f" % b for b in self.eigen_vectors.T[i]]) 
     1498            #          for i, a in enumerate(self.input_domain.attributes) 
     1499            #          ]) 
     1500        ]) if len(self.pc_domain) <= ncomponents else\ 
     1501        "\n".join([ 
     1502            "PCA SUMMARY", 
     1503            "", 
     1504            "Std. deviation of components:", 
     1505            " ".join(["              "] + 
     1506                     ["%10s" % a.name for a in self.pc_domain.attributes[:ncomponents]] + 
     1507                     ["%10s" % "..."] + 
     1508                     ["%10s" % self.pc_domain.attributes[-1].name]), 
     1509            " ".join(["Std. deviation"] + 
     1510                     ["%10.3f" % a for a in self.eigen_values[:ncomponents]] + 
     1511                     ["%10s" % ""] + 
     1512                     ["%10.3f" % self.eigen_values[-1]]), 
     1513            " ".join(["Proportion Var"] + 
     1514                     ["%10.3f" % a for a in self.eigen_values[:ncomponents] / s * 100] + 
     1515                     ["%10s" % ""] + 
     1516                     ["%10.3f" % (self.eigen_values[-1] / s * 100)]), 
     1517            " ".join(["Cumulative Var"] + 
     1518                     ["%10.3f" % a for a in cs[:ncomponents] * 100] + 
     1519                     ["%10s" % ""] + 
     1520                     ["%10.3f" % (cs[-1] * 100)]), 
     1521            "", 
     1522            #"Loadings:", 
     1523            #" ".join(["%16s" % ""] + 
     1524            #         ["%8s" % a.name for a in self.pc_domain.attributes[:ncomponents]] + 
     1525            #         ["%8s" % "..."] + 
     1526            #         ["%8s" % self.pc_domain.attributes[-1].name]), 
     1527            #"\n".join([ 
     1528            #    " ".join(["%16.16s" %a.name] + 
     1529            #             ["%8.3f" % b for b in self.eigen_vectors.T[i, :ncomponents]] + 
     1530            #             ["%8s" % ""] + 
     1531            #             ["%8.3f" % self.eigen_vectors.T[i, -1]]) 
     1532            #          for i, a in enumerate(self.input_domain.attributes) 
     1533            #          ]) 
     1534        ]) 
     1535 
     1536 
     1537 
     1538    ################ Plotting functions ################### 
     1539 
     1540    def scree_plot(self, filename = None, title = 'Scree plot'): 
     1541        """ 
     1542        Draw a scree plot of principal components 
     1543 
     1544        :param filename: Name of the file to which the plot will be saved. \ 
     1545        If None, plot will be displayed instead. 
     1546        :type filename: str 
     1547        :param title: Plot title 
     1548        :type title: str 
     1549        """ 
     1550        import pylab as plt 
     1551 
     1552        s = self.variance_sum 
     1553        vc = self.eigen_values / s 
     1554        cs = numpy.cumsum(self.eigen_values) / s 
     1555 
     1556        fig = plt.figure() 
     1557        ax = fig.add_subplot(111) 
     1558 
     1559        x_axis = range(len(self.eigen_values)) 
     1560        x_labels = ["PC%d" % (i + 1, ) for i in x_axis] 
     1561 
     1562        ax.set_xticks(x_axis) 
     1563        ax.set_xticklabels(x_labels) 
     1564        plt.setp(ax.get_xticklabels(), "rotation", 90) 
     1565        plt.grid(True) 
     1566 
     1567        ax.set_xlabel('Principal components') 
     1568        ax.set_ylabel('Proportion of Variance') 
     1569        ax.set_title(title + "\n") 
     1570        ax.plot(x_axis, vc, color="red") 
     1571        ax.scatter(x_axis, vc, color="red", label="Variance") 
     1572 
     1573        ax.plot(x_axis, cs, color="orange") 
     1574        ax.scatter(x_axis, cs, color="orange", label="Cumulative Variance") 
     1575        ax.legend(loc=0) 
     1576 
     1577        ax.axis([-0.5, len(self.eigen_values) - 0.5, 0, 1]) 
     1578 
     1579        if filename: 
     1580            plt.savefig(filename) 
     1581        else: 
     1582            plt.show() 
     1583 
     1584    def biplot(self, filename = None, components = [0,1], title = 'Biplot'): 
     1585        """ 
     1586        Draw biplot for PCA. Actual projection must be performed via pca(data) 
     1587        before bipot can be used. 
     1588 
     1589        :param filename: Name of the file to which the plot will be saved. \ 
     1590        If None, plot will be displayed instead. 
     1591        :type plot: str 
     1592        :param components: List of two components to plot. 
     1593        :type components: list 
     1594        :param title: Plot title 
     1595        :type title: str 
     1596        """ 
     1597        import pylab as plt 
     1598 
     1599        if len(components) < 2: 
     1600            raise orange.KernelException, 'Two components are needed for biplot' 
     1601 
     1602        if not (0 <= min(components) <= max(components) < len(self.eigen_values)): 
     1603            raise orange.KernelException, 'Invalid components' 
     1604 
     1605        X = self.A[:,components[0]] 
     1606        Y = self.A[:,components[1]] 
     1607 
     1608        vectorsX = self.eigen_vectors[:,components[0]] 
     1609        vectorsY = self.eigen_vectors[:,components[1]] 
     1610 
     1611 
     1612        #TO DO -> pc.biplot (maybe) 
     1613        #trDataMatrix = dataMatrix / lam 
     1614        #trLoadings = loadings * lam 
     1615 
     1616        #max_data_value = numpy.max(abs(trDataMatrix)) * 1.05 
     1617        max_load_value = self.eigen_vectors.max() * 1.5 
     1618 
     1619        #plt.clf() 
     1620        fig = plt.figure() 
     1621        ax1 = fig.add_subplot(111) 
     1622        ax1.set_title(title + "\n") 
     1623        ax1.set_xlabel("PC%s (%d%%)" % (components[0], self.eigen_values[components[0]] / self.variance_sum * 100)) 
     1624        ax1.set_ylabel("PC%s (%d%%)" % (components[1], self.eigen_values[components[1]] / self.variance_sum * 100)) 
     1625        ax1.xaxis.set_label_position('bottom') 
     1626        ax1.xaxis.set_ticks_position('bottom') 
     1627        ax1.yaxis.set_label_position('left') 
     1628        ax1.yaxis.set_ticks_position('left') 
     1629 
     1630        #if self._classArray == None: 
     1631        #trDataMatrix = transpose(trDataMatrix) 
     1632        ax1.plot(X, Y, Colors[0]) 
     1633        #else: 
     1634        #suboptimal 
     1635        #    classValues = [] 
     1636        #    for classValue in self._classArray: 
     1637        #        if classValue not in classValues: 
     1638        #            classValues.append(classValue) 
     1639        #    for i in range(len(classValues)): 
     1640        #        choice = numpy.array([classValues[i] == cv for cv in self._classArray]) 
     1641        #        partialDataMatrix = transpose(trDataMatrix[choice]) 
     1642        #        ax1.plot(partialDataMatrix[0], partialDataMatrix[1], 
     1643        #                 Colors[i % len(Colors)], label = str(classValues[i])) 
     1644        #    ax1.legend() 
     1645 
     1646        #ax1.set_xlim(-max_data_value, max_data_value) 
     1647        #ax1.set_ylim(-max_data_value, max_data_value) 
     1648 
     1649        #eliminate double axis on right 
     1650        ax0 = ax1.twinx() 
     1651        ax0.yaxis.set_visible(False) 
     1652 
     1653        ax2 = ax0.twiny() 
     1654        ax2.xaxis.set_label_position('top') 
     1655        ax2.xaxis.set_ticks_position('top') 
     1656        ax2.yaxis.set_label_position('right') 
     1657        ax2.yaxis.set_ticks_position('right') 
     1658        for tl in ax2.get_xticklabels(): 
     1659            tl.set_color('r') 
     1660        for tl in ax2.get_yticklabels(): 
     1661            tl.set_color('r') 
     1662 
     1663        arrowprops = dict(facecolor = 'red', edgecolor = 'red', width = 1, headwidth = 4) 
     1664 
     1665        for (x, y, a) in zip(vectorsX, vectorsY,self.input_domain.attributes): 
     1666            if max(x, y) < 0.1: 
     1667                continue 
     1668            print x, y, a 
     1669            ax2.annotate('', (x, y), (0, 0), arrowprops = arrowprops) 
     1670            ax2.text(x * 1.1, y * 1.2, a.name, color = 'red') 
     1671 
     1672        ax2.set_xlim(-max_load_value, max_load_value) 
     1673        ax2.set_ylim(-max_load_value, max_load_value) 
     1674 
     1675        if filename: 
     1676            plt.savefig(filename) 
     1677        else: 
     1678            plt.show() 
     1679 
     1680 
     1681class Fda(object): 
     1682    """ 
     1683    Construct a linear projection of data using FDA. When using this projection optimization method, data is always 
     1684    standardized prior to being projected. 
     1685 
     1686    If data instances are provided to the constructor, 
     1687    the optimization algorithm is called and the resulting projector 
     1688    (:class:`~Orange.projection.linear.FdaProjector`) is 
     1689    returned instead of the optimizer (instance of this class). 
     1690 
     1691    :rtype: :class:`~Orange.projection.linear.Fda` or 
     1692            :class:`~Orange.projection.linear.FdaProjector` 
     1693    """ 
     1694 
     1695    def __new__(cls, data = None): 
     1696        self = object.__new__(cls) 
     1697        if data: 
     1698            self.__init__() 
     1699            return self.__call__(data) 
     1700        else: 
     1701            return self 
     1702 
     1703    def __call__(self, dataset): 
     1704        """ 
     1705        Perform a FDA analysis on a data set and return a linear projector 
     1706        that maps data into another vector space. 
     1707 
     1708        :param dataset: input data set. 
     1709        :type dataset: :class:`Orange.data.Table` 
     1710 
     1711        :rtype: :class:`~Orange.projection.linear.FdaProjector` 
     1712        """ 
     1713        X, Y = dataset.to_numpy_MA("a/c") 
     1714 
     1715        Xm = numpy.mean(X, axis=0) 
     1716        X = X - Xm 
     1717 
     1718        #take care of the constant features 
     1719        stdev = numpy.std(X, axis=0) 
     1720        relevant_features = stdev != 0 
     1721        stdev[stdev == 0] = 1. 
     1722        X /= stdev 
     1723        X = X[:,relevant_features] 
     1724 
     1725        instances, features = X.shape 
     1726        class_count = len(set(Y)) 
     1727        # special case when we have two classes 
     1728        if class_count == 2: 
     1729            data1 = MA.take(X, numpy.argwhere(Y == 0).flatten(), axis=0) 
     1730            data2 = MA.take(X, numpy.argwhere(Y != 0).flatten(), axis=0) 
     1731            miDiff = MA.average(data1, axis=1) - MA.average(data2, axis=1) 
     1732            covMatrix = (MA.dot(data1.T, data1) + MA.dot(data2.T, data2)) / instances 
     1733            U = numpy.linalg.inv(covMatrix) * miDiff 
     1734            D = numpy.array([1]) 
     1735        else: 
     1736            # compute means and average covariances of examples in each class group 
     1737            Sw = MA.zeros([features, features]) 
     1738            for v in set(Y): 
     1739                d = MA.take(X, numpy.argwhere(Y == v).flatten(), axis=0) 
     1740                d = d - numpy.mean(d, axis=0) 
     1741                Sw += MA.dot(d.T, d) 
     1742            Sw /= instances 
     1743            total = MA.dot(X.T, X)/float(instances) 
     1744            Sb = total - Sw 
     1745 
     1746            matrix = numpy.linalg.inv(Sw)*Sb 
     1747            D, U = numpy.linalg.eigh(matrix) 
     1748 
     1749        sorted_indices = [i for _,i in sorted([(ev, i) 
     1750                          for i, ev in enumerate(D)], reverse=True)] 
     1751        U = numpy.take(U, sorted_indices, axis = 1) 
     1752        D = numpy.take(D, sorted_indices) 
     1753 
     1754        #insert zeros for constant features 
     1755        n, m = U.shape 
     1756        if m != M: 
     1757            U_ = numpy.zeros((n,M)) 
     1758            U_[:,relevant_features] = U 
     1759            U = U_ 
     1760 
     1761        out_domain = Orange.data.Domain([Orange.feature.Continuous("Comp.%d"% 
     1762                                                                  (i+1)) for 
     1763                                         i in range(len(D))], False) 
     1764 
     1765        return FdaProjector(input_domain = dataset.domain, 
     1766            output_domain = out_domain, 
     1767            mean = Xm, 
     1768            stdev = stdev, 
     1769            standardize = True, 
     1770            eigen_vectors = U, 
     1771            projection = U, 
     1772            eigen_values = D) 
     1773 
     1774class FdaProjector(Projector): 
     1775    """ 
     1776    .. attribute:: eigen_vectors 
     1777 
     1778        Synonymous for :obj:`~Orange.projection.linear.Projector.projection`. 
     1779 
     1780    .. attribute:: eigen_values 
     1781 
     1782        Array containing eigenvalues corresponding to eigenvectors. 
     1783 
     1784    """ 
     1785 
     1786    def __init__(self, **kwds): 
     1787        self.__dict__.update(kwds) 
     1788 
     1789 
     1790 
    11171791@deprecated_keywords({"dataMatrix": "data_matrix", 
    11181792                      "classArray": "class_array", 
     
    11201794                      "useGeneralizedEigenvectors": "use_generalized_eigenvectors"}) 
    11211795def create_pca_projection(data_matrix, class_array = None, ncomps = -1, use_generalized_eigenvectors = 1): 
     1796    import warnings 
     1797    warnings.warn("Deprecated in favour of Orange" 
     1798                  ".projection.linear.Pca.", 
     1799        DeprecationWarning) 
    11221800    if type(data_matrix) == numpy.ma.core.MaskedArray: 
    11231801        data_matrix = numpy.array(data_matrix) 
    11241802    if class_array != None and type(class_array) == numpy.ma.core.MaskedArray: 
    11251803        class_array = numpy.array(class_array) 
    1126          
     1804 
    11271805    data_matrix = numpy.transpose(data_matrix) 
    11281806 
     
    11591837    vals, vectors = eig(matrix) 
    11601838    if vals.dtype.kind == "c":       # if eigenvalues are complex numbers then do nothing 
    1161          return None, None 
     1839        return None, None 
    11621840    vals = list(vals) 
    1163      
     1841 
    11641842    if ncomps == -1: 
    11651843        ncomps = len(vals) 
    11661844    ncomps = min(ncomps, len(vals)) 
    1167      
     1845 
    11681846    ret_vals = [] 
    11691847    ret_indices = [] 
     
    11731851        ret_indices.append(bestind) 
    11741852        vals[bestind] = -1 
    1175      
     1853 
    11761854    return ret_vals, numpy.take(vectors.T, ret_indices, axis = 0)         # i-th eigenvector is the i-th column in vectors so we have to transpose the array 
    11771855 
    11781856createPCAProjection = create_pca_projection 
    1179  
    1180  
    1181 # ############################################################################# 
    1182 # class that represents freeviz classifier 
    1183 class FreeVizClassifier(Orange.classification.Classifier): 
    1184     """ 
    1185     A kNN classifier on the 2D projection of the data, optimized by FreeViz. 
    1186      
    1187     Usually the learner 
    1188     (:class:`Orange.projection.linear.FreeVizLearner`) is used to construct the 
    1189     classifier. 
    1190      
    1191     When constructing the classifier manually, the following parameters can 
    1192     be passed: 
    1193      
    1194     :param data: table of data instances to project to a 2D plane and use for 
    1195         classification. 
    1196     :type data: :class:`Orange.data.Table` 
    1197      
    1198     :param freeviz: the FreeViz algorithm instance to use to optimize the 2D 
    1199         projection. 
    1200     :type freeviz: :class:`Orange.projection.linear.FreeViz` 
    1201      
    1202     """ 
    1203      
    1204     def __init__(self, data, freeviz): 
    1205         self.freeviz = freeviz 
    1206  
    1207         if self.freeviz.__class__ != FreeViz: 
    1208             self.freeviz.parentWidget.setData(data) 
    1209             self.freeviz.parentWidget.show_all_attributes = 1 
    1210         else: 
    1211             self.freeviz.graph.setData(data) 
    1212             self.freeviz.show_all_attributes() 
    1213  
    1214         #self.FreeViz.randomAnchors() 
    1215         self.freeviz.radial_anchors() 
    1216         self.freeviz.optimize_separation() 
    1217  
    1218         graph = self.freeviz.graph 
    1219         ai = graph.attributeNameIndex 
    1220         labels = [a[2] for a in graph.anchorData] 
    1221         indices = [ai[label] for label in labels] 
    1222  
    1223         valid_data = graph.getValidList(indices) 
    1224         domain = Orange.data.Domain([graph.dataDomain[i].name for i in indices]+ 
    1225                                [graph.dataDomain.classVar.name], 
    1226                                graph.dataDomain) 
    1227         offsets = [graph.attrValues[graph.attributeNames[i]][0] 
    1228                    for i in indices] 
    1229         normalizers = [graph.getMinMaxVal(i) for i in indices] 
    1230         selected_data = numpy.take(graph.originalData, indices, axis = 0) 
    1231         averages = numpy.average(numpy.compress(valid_data, selected_data, 
    1232                                                 axis=1), 1) 
    1233         class_data = numpy.compress(valid_data, 
    1234                                     graph.originalData[graph.dataClassIndex]) 
    1235  
    1236         graph.createProjectionAsNumericArray(indices, useAnchorData = 1, 
    1237                                              removeMissingData = 0, 
    1238                                              valid_data = valid_data, 
    1239                                              jitterSize = -1) 
    1240         self.classifier = Orange.classification.knn.P2NN(domain, 
    1241                                       numpy.transpose(numpy.array([numpy.compress(valid_data, 
    1242                                                                                   graph.unscaled_x_positions), 
    1243                                                                    numpy.compress(valid_data, 
    1244                                                                                   graph.unscaled_y_positions), 
    1245                                                                    class_data])), 
    1246                                       graph.anchorData, offsets, normalizers, 
    1247                                       averages, graph.normalizeExamples, law=1) 
    1248  
    1249     # for a given instance run argumentation and find out to which class it most often fall 
    1250     @deprecated_keywords({"example": "instance", "returnType": "return_type"}) 
    1251     def __call__(self, instance, return_type=Orange.classification.Classifier.GetValue): 
    1252         #instance.setclass(0) 
    1253         return self.classifier(instance, return_type) 
    1254  
    1255 FreeVizClassifier = deprecated_members({"FreeViz":"freeviz"})(FreeVizClassifier) 
    1256  
    1257 class FreeVizLearner(Orange.classification.Learner): 
    1258     """ 
    1259     A learner that builds a :class:`FreeVizClassifier` on given data. An 
    1260     instance of :class:`FreeViz` can be passed to the constructor as a 
    1261     keyword argument :obj:`freeviz`.     
    1262  
    1263     If data instances are provided to the constructor, the learning algorithm 
    1264     is called and the resulting classifier is returned instead of the learner. 
    1265      
    1266     """ 
    1267     def __new__(cls, freeviz = None, instances = None, weight_id = 0, **argkw): 
    1268         self = Orange.classification.Learner.__new__(cls, **argkw) 
    1269         if instances: 
    1270             self.__init__(freeviz, **argkw) 
    1271             return self.__call__(instances, weight_id) 
    1272         else: 
    1273             return self 
    1274  
    1275     def __init__(self, freeviz = None): 
    1276         if not freeviz: 
    1277             freeviz = FreeViz() 
    1278         self.freeviz = freeviz 
    1279         self.name = "freeviz Learner" 
    1280  
    1281     @deprecated_keywords({"examples": "instances", "weightID": "weight_id"}) 
    1282     def __call__(self, instances, weight_id = 0): 
    1283         return FreeVizClassifier(instances, self.freeviz) 
    1284  
    1285 FreeVizLearner = deprecated_members({"FreeViz":"freeviz"})(FreeVizLearner) 
    1286  
    1287  
    1288 class S2NHeuristicLearner(Orange.classification.Learner): 
    1289     """ 
    1290     This class is not documented yet. 
    1291      
    1292     """ 
    1293     def __new__(cls, freeviz = None, instances = None, weight_id = 0, **argkw): 
    1294         self = Orange.classification.Learner.__new__(cls, **argkw) 
    1295         if instances: 
    1296             self.__init__(freeviz, **argkw) 
    1297             return self.__call__(instances, weight_id) 
    1298         else: 
    1299             return self 
    1300  
    1301     def __init__(self, freeviz = None): 
    1302         if not freeviz: 
    1303             freeviz = FreeViz() 
    1304         self.freeviz = freeviz 
    1305         self.name = "S2N Feature Selection Learner" 
    1306  
    1307     @deprecated_keywords({"examples": "instances", "weightID": "weight_id"}) 
    1308     def __call__(self, instances, weight_id = 0): 
    1309         return S2NHeuristicClassifier(instances, self.freeviz) 
    1310  
    1311 S2NHeuristicLearner = deprecated_members({"FreeViz": 
    1312                                           "freeviz"})(S2NHeuristicLearner) 
Note: See TracChangeset for help on using the changeset viewer.