Exemple #1
0
    def _predict(self, state, calcTransitions=False):
        '''
        Predict the changes.
        '''
        try:
            self.rangeChanged.emit(self.tr("Initialize model %p%"), 1)

            rows, cols = self.geodata['ySize'], self.geodata['xSize']
            if not self.changeMap.geoDataMatch(state):
                raise WoeManagerError('Geometries of the state and changeMap rasters are different!')

            prediction = np.zeros((rows,cols), dtype=np.uint8)
            confidence = np.zeros((rows,cols), dtype=np.uint8)
            mask = np.zeros((rows,cols), dtype=np.byte)

            stateBand = state.getBand(1)

            self.updateProgress.emit()
            self.rangeChanged.emit(self.tr("Prediction %p%"), rows)

            for r in xrange(rows):
                for c in xrange(cols):
                    oldMax, currMax = -1000, -1000  # Small numbers
                    indexMax = -1                   # Index of Max weight
                    initCat = stateBand[r,c]        # Init category (state before transition)
                    try:
                        codes = self.analyst.codes(initCat)   # Possible final states
                        for code in codes:
                            try: # If not all possible transitions are presented in the changeMap
                                map = self.woe[code]     # Get WoE map of transition 'code'
                            except KeyError:
                                continue
                            w = map[r,c]        # The weight in the (r,c)-pixel
                            if w > currMax:
                                indexMax, oldMax, currMax = code, currMax, w
                        prediction[r,c] = indexMax
                        confidence[r,c] = int(100*(sigmoid(currMax) - sigmoid(oldMax)))
                    except ValueError:
                        mask[r,c] = 1
                self.updateProgress.emit()

            predicted_band = np.ma.array(data=prediction, mask=mask, dtype=np.uint8)
            self.prediction = Raster()
            self.prediction.create([predicted_band], self.geodata)
            confidence_band = np.ma.array(data=confidence, mask=mask, dtype=np.uint8)
            self.confidence = Raster()
            self.confidence.create([confidence_band], self.geodata)
        except MemoryError:
            self.errorReport.emit(self.tr("The system out of memory during WOE prediction"))
            raise
        except:
            self.errorReport.emit(self.tr("An unknown error occurs during WoE prediction"))
            raise
        finally:
            self.processFinished.emit()
Exemple #2
0
 def errorMap(self, answer):
     '''
     Create map of correct and incorrect prediction.
     This function compares the known answer and the result of predicting procedure,
     correct pixel is marked as 0.
     '''
     state = self.getState()
     b = state.getBand(1)
     a = answer.getBand(1)
     diff = (a-b).astype(np.int16)
     result = Raster()
     result.create([diff], state.getGeodata())
     return result
Exemple #3
0
    def train(self):
        '''
        Train the model
        '''
        self.transitionPotentials = {}
        try:
            iterCount = len(self.codes)*len(self.factors)
            self.rangeChanged.emit(self.tr("Training WoE... %p%"), iterCount)
            changeMap = self.changeMap.getBand(1)
            for code in self.codes:
                sites = binaryzation(changeMap, [code])
                # Reclass factors (continuous factor -> ordinal factor)
                wMap = np.ma.zeros(changeMap.shape) # The map of summary weight of the all factors
                self.weights[code] = {}             # Dictionary for storing wheights of every raster's band
                for k in xrange(len(self.factors)):
                    fact = self.factors[k]
                    self.weights[code][k] = {}      # Weights of the factor
                    factorW = self.weights[code][k]
                    if self.bins: # Get bins of the factor
                        bin = self.bins[k]
                        if (bin != None) and fact.getBandsCount() != len(bin):
                            raise WoeManagerError("Count of bins list for multiband factor is't equal to band count!")
                    else: bin = None
                    for i in range(1, fact.getBandsCount()+1):
                        band = fact.getBand(i)
                        if bin and bin[i-1]: #
                            band = reclass(band, bin[i-1])
                        band, sites = masks_identity(band, sites, dtype=np.uint8)   # Combine masks of the rasters
                        woeRes = woe(band, sites, self.unit_cell)   # WoE for the 'code' (initState->finalState) transition and current 'factor'.
                        weights = woeRes['map']
                        wMap = wMap + weights
                        factorW[i] = woeRes['weights']
                    self.updateProgress.emit()

                # Reclassification finished => set WoE coefficients
                self.woe[code]=wMap             # WoE for all factors and the transition code.

                # Potentials are WoE map rescaled to 0--100 percents
                band = (sigmoid(wMap)*100).astype(np.uint8)
                p = Raster()
                p.create([band], self.geodata)
                self.transitionPotentials[code] = p
                gc.collect()
        except MemoryError:
            self.errorReport.emit('The system out of memory during WoE trainig')
            raise
        except:
            self.errorReport.emit(self.tr("An unknown error occurs during WoE trainig"))
            raise
        finally:
            self.processFinished.emit()
Exemple #4
0
    def makeChangeMap(self):
        rows, cols = self.geodata['ySize'], self.geodata['xSize']
        band = np.zeros([rows, cols], dtype=np.int16)

        f, s = self.first, self.second
        if self.initRaster == None:
            checkPersistent = False
        else:
            checkPersistent = True
            t = self.initRaster.getBand(1)
        raster = None
        try:
            self.rangeChanged.emit(self.tr("Creating change map %p%"), rows)
            for i in xrange(rows):
                for j in xrange(cols):
                    if (f.mask.shape == ()) or (not f.mask[i,j]):
                        r = f[i,j]
                        c = s[i,j]
                        # Percistent category is the category that is constant for all three rasters
                        if checkPersistent and (r==c) and (r==t[i,j]):
                            band[i, j] = self.persistentCategoryCode
                        else:
                            band[i, j] = self.encode(r, c)
                self.updateProgress.emit()
            bands = [np.ma.array(data = band, mask = f.mask, dtype=np.int16)]
            raster = Raster()
            raster.create(bands, self.geodata)
            self.changeMap = raster
        except MemoryError:
            self.errorReport.emit(self.tr("The system out of memory during change map creating"))
            raise
        except:
            self.errorReport.emit(self.tr("An unknown error occurs during change map creating"))
            raise
        finally:
            self.processFinished.emit(raster)
Exemple #5
0
    def __sim(self):
        '''
        1 iteracion of simulation.
        '''
        transition = self.crosstable.getCrosstable()
        #self.errorReport.emit(self.tr("transition\n%s\n") % transition.getCrossTable())
        
        self.updatePrediction(self.state)
        changes = self.getPrediction().getBand(1)   # Predicted change map
        changes = changes + 1                       # Filling nodata as 0 can be ambiguous:
        changes = np.ma.filled(changes, 0)          #   (cat_code can be 0, to do not mix it with no-data, add 1)
        state = self.getState()
        new_state = state.getBand(1).copy().astype(np.uint8)    # New states (the result of simulation) will be stored there.

        self.rangeChanged.emit(self.tr("Area Change Analysis %p%"), 2)
        self.updateProgress.emit()
        QCoreApplication.processEvents()
        analyst = AreaAnalyst(state, second = None)
        self.updateProgress.emit()
        QCoreApplication.processEvents()

        categories = state.getBandGradation(1)

        # Make transition between categories according to
        # number of moved pixel in crosstable
        self.rangeChanged.emit(self.tr("Simulation process %p%"), len(categories)**2 - len(categories))
        QCoreApplication.processEvents()
        for initClass in categories:
            for finalClass in categories:
                if initClass == finalClass: continue

                # TODO: Calculate number of pixels to be moved via TransitionMatrix and state raster
                n = transition.getTransition(initClass, finalClass)   # Number of pixels that have to be
                                                                      # changed the categories
                                                                      # (use TransitoionMatrix only).
                                                                     
                if n==0:
                    continue
                # Find n appropriate places for transition initClass -> finalClass
                cat_code = analyst.encode(initClass, finalClass)
                # Array of places where transitions initClass -> finalClass are occured
                places = (changes==cat_code+1)  # cat_code can be 0, do not mix it with no-data in 'changes' variable
                placesCount = np.sum(places)
                # print "cat_code, placesCount, n", cat_code, placesCount

                if placesCount < n:
                    self.logMessage.emit(self.tr("There are more transitions in the transition matrix, then the model have found"))
                    # print "There are more transitions in the transition matrix, then the model have found"
                    # print "cat_code, placesCount, n", cat_code, placesCount, n
                    QCoreApplication.processEvents()
                    n = placesCount
                if n >0:
                    confidence = self.getConfidence().getBand(1)
                    # Add some random value
                    rnd = np.random.sample(size=confidence.shape)/1000 # A small random
                    confidence = np.ma.filled(confidence, 0) + rnd
                    confidence = confidence * places # The higher is number in cell, the higer is probability of transition in the cell.

                    # Ensure, n is bigger then nonzero confidence
                    placesCount = np.sum(confidence>0)
                    if placesCount < n: # Some confidence where transitions has to be appear is zero. The transition count will be cropped.
                        # print "Some confidence is zero. cat_code, nonzeroConf, wantedPixels", cat_code, placesCount, n
                        n = placesCount

                    ind = confidence.argsort(axis=None)[-n:]
                    indices = [np.unravel_index(i, confidence.shape) for i in ind]

                    # Now "indices" contains indices of the appropriate places,
                    # make transition initClass -> finalClass
                    r1 = np.zeros(confidence.shape)
                    for index in indices:
                        new_state[index] = finalClass

                self.updateProgress.emit()
                QCoreApplication.processEvents()

        result = Raster()
        result.create([new_state], state.getGeodata())
        self.state = result
Exemple #6
0
class WoeManager(QObject):
    '''This class gets the data extracted from the UI and
    pass it to woe function, then gets and stores the result.
    '''

    rangeChanged = pyqtSignal(str, int)
    updateProgress = pyqtSignal()
    processFinished = pyqtSignal()
    logMessage = pyqtSignal(str)
    errorReport = pyqtSignal(str)

    def __init__(self, factors, areaAnalyst, unit_cell=1, bins = None):
        '''
        @param factors      List of the pattern rasters used for prediction of point objects (sites).
        @param areaAnalyst  AreaAnalyst that contains map of the changes, encodes and decodes category numbers.
        @param unit_cell    Method parameter, pixelsize of resampled rasters.
        @param bins         Dictionary of bins. Bins are binning boundaries that used for reduce count of categories.
                                For example if factors = [f0, f1], then bins could be (for example) {0:[bins for f0], 1:[bins for f1]} = {0:[[10, 100, 250]],1:[[0.2, 1, 1.5, 4]]}.
                                List of list used because a factor can be a multiband raster, we need get a list of bins for every band. For example:
                                factors = [f0, 2-band-factor], bins= {0: [[10, 100, 250]], 1:[[0.2, 1, 1.5, 4], [3, 4, 7]] }
        '''

        QObject.__init__(self)

        self.factors = factors
        self.analyst = areaAnalyst
        self.changeMap  = areaAnalyst.getChangeMap()
        self.bins       = bins
        self.unit_cell  = unit_cell

        self.prediction = None      # Raster of the prediction results
        self.confidence = None      # Raster of the results confidence(1 = the maximum confidence, 0 = the least confidence)

        if (bins != None) and (len(self.factors) != len(bins.keys())):
            raise WoeManagerError('Lengths of bins and factors are different!')

        for r in self.factors:
            if not self.changeMap.geoDataMatch(r):
                raise WoeManagerError('Geometries of the input rasters are different!')

        if self.changeMap.getBandsCount() != 1:
            raise WoeManagerError('Change map must have one band!')

        self.geodata = self.changeMap.getGeodata()

        # Denormalize factors if they are normalized
        for r in self.factors:
            r.denormalize()

        # Get list of codes from the changeMap raster
        categories = self.changeMap.getBandGradation(1)

        self.codes = [int(c) for c in categories]    # Codes of transitions initState->finalState (see AreaAnalyst.encode)
        self.woe = {}       # Maps of WoE results of every transition code

        self.weights = {}   # Weights of WoE (of raster band code)
        #{ # The format is: {Transition_code: {factorNumber1: [list of the weights], factorNumber2: [list of the weights]}, ...}
        #  # for example:
        #   0: {0: {1: [...]}, 1: {1: [...]}},
        #   1: {0: {1: [...]}, 1: {1: [...]}},
        #   2: {0: {1: [...]}, 1: {1: [...]}},
        #   ...
        #}
        #
        self.transitionPotentials = None # Dictionary of transition potencial maps: {category1: map1, category2: map2, ...}

    def checkBins(self):
        """
        Check if bins are applicable to the factors
        """
        if self.bins != None:
            for i, factor in enumerate(self.factors):
                factor.denormalize()
                bin = self.bins[i]
                if (bin != None) and (bin != [None]):
                    for j in range(factor.getBandsCount()):
                        b = bin[j]
                        tmp = b[:]
                        tmp.sort()
                        if b!=tmp: # Mast be sorted
                            return False
                        b0, bMax = b[0], b[len(b)-1]
                        bandStat = factor.getBandStat(j+1)
                        if bandStat['min'] >b0 or bandStat['max']<bMax:
                            return False
        return True

    def getConfidence(self):
        return self.confidence

    def getPrediction(self, state, factors=None, calcTransitions=False):
        '''
        Most of the models use factors for prediction, but WoE takes list of factors only once (during the initialization).
        '''
        self._predict(state, calcTransitions)
        return self.prediction

    def getTransitionPotentials(self):
        return self.transitionPotentials

    def getWoe(self):
        return self.woe

    def _predict(self, state, calcTransitions=False):
        '''
        Predict the changes.
        '''
        try:
            self.rangeChanged.emit(self.tr("Initialize model %p%"), 1)

            rows, cols = self.geodata['ySize'], self.geodata['xSize']
            if not self.changeMap.geoDataMatch(state):
                raise WoeManagerError('Geometries of the state and changeMap rasters are different!')

            prediction = np.zeros((rows,cols), dtype=np.uint8)
            confidence = np.zeros((rows,cols), dtype=np.uint8)
            mask = np.zeros((rows,cols), dtype=np.byte)

            stateBand = state.getBand(1)

            self.updateProgress.emit()
            self.rangeChanged.emit(self.tr("Prediction %p%"), rows)

            for r in xrange(rows):
                for c in xrange(cols):
                    oldMax, currMax = -1000, -1000  # Small numbers
                    indexMax = -1                   # Index of Max weight
                    initCat = stateBand[r,c]        # Init category (state before transition)
                    try:
                        codes = self.analyst.codes(initCat)   # Possible final states
                        for code in codes:
                            try: # If not all possible transitions are presented in the changeMap
                                map = self.woe[code]     # Get WoE map of transition 'code'
                            except KeyError:
                                continue
                            w = map[r,c]        # The weight in the (r,c)-pixel
                            if w > currMax:
                                indexMax, oldMax, currMax = code, currMax, w
                        prediction[r,c] = indexMax
                        confidence[r,c] = int(100*(sigmoid(currMax) - sigmoid(oldMax)))
                    except ValueError:
                        mask[r,c] = 1
                self.updateProgress.emit()

            predicted_band = np.ma.array(data=prediction, mask=mask, dtype=np.uint8)
            self.prediction = Raster()
            self.prediction.create([predicted_band], self.geodata)
            confidence_band = np.ma.array(data=confidence, mask=mask, dtype=np.uint8)
            self.confidence = Raster()
            self.confidence.create([confidence_band], self.geodata)
        except MemoryError:
            self.errorReport.emit(self.tr("The system out of memory during WOE prediction"))
            raise
        except:
            self.errorReport.emit(self.tr("An unknown error occurs during WoE prediction"))
            raise
        finally:
            self.processFinished.emit()

    def train(self):
        '''
        Train the model
        '''
        self.transitionPotentials = {}
        try:
            iterCount = len(self.codes)*len(self.factors)
            self.rangeChanged.emit(self.tr("Training WoE... %p%"), iterCount)
            changeMap = self.changeMap.getBand(1)
            for code in self.codes:
                sites = binaryzation(changeMap, [code])
                # Reclass factors (continuous factor -> ordinal factor)
                wMap = np.ma.zeros(changeMap.shape) # The map of summary weight of the all factors
                self.weights[code] = {}             # Dictionary for storing wheights of every raster's band
                for k in xrange(len(self.factors)):
                    fact = self.factors[k]
                    self.weights[code][k] = {}      # Weights of the factor
                    factorW = self.weights[code][k]
                    if self.bins: # Get bins of the factor
                        bin = self.bins[k]
                        if (bin != None) and fact.getBandsCount() != len(bin):
                            raise WoeManagerError("Count of bins list for multiband factor is't equal to band count!")
                    else: bin = None
                    for i in range(1, fact.getBandsCount()+1):
                        band = fact.getBand(i)
                        if bin and bin[i-1]: #
                            band = reclass(band, bin[i-1])
                        band, sites = masks_identity(band, sites, dtype=np.uint8)   # Combine masks of the rasters
                        woeRes = woe(band, sites, self.unit_cell)   # WoE for the 'code' (initState->finalState) transition and current 'factor'.
                        weights = woeRes['map']
                        wMap = wMap + weights
                        factorW[i] = woeRes['weights']
                    self.updateProgress.emit()

                # Reclassification finished => set WoE coefficients
                self.woe[code]=wMap             # WoE for all factors and the transition code.

                # Potentials are WoE map rescaled to 0--100 percents
                band = (sigmoid(wMap)*100).astype(np.uint8)
                p = Raster()
                p.create([band], self.geodata)
                self.transitionPotentials[code] = p
                gc.collect()
        except MemoryError:
            self.errorReport.emit('The system out of memory during WoE trainig')
            raise
        except:
            self.errorReport.emit(self.tr("An unknown error occurs during WoE trainig"))
            raise
        finally:
            self.processFinished.emit()

    def weightsToText(self):
        '''
        Format self.weights as text report.
        '''
        if self.weights == {}:
            return u""
        text = u""
        for code in self.codes:
            (initClass, finalClass) = self.analyst.decode(code)
            text = text + self.tr("Transition %s -> %s\n" % (int(initClass), int(finalClass)))
            try:
                factorW = self.weights[code]
                for factNum, factDict in factorW.iteritems():
                    name = self.factors[factNum].getFileName()
                    name = basename(name)
                    text = text + self.tr("\t factor: %s \n" % (name,) )
                    for bandNum, bandWeights in factDict.iteritems():
                        weights = ["%f" % (w,) for w in bandWeights]
                        text = text + self.tr("\t\t Weights of band %s: %s \n" % (bandNum, ", ".join(weights)) )
            except:
                text = text + self.tr('W for code % s (%s -> %s) causes error' % (code, initClass, finalClass))
                raise
        return text
Exemple #7
0
class LR(QObject):
    """
    Implements Logistic Regression model definition and calibration
    (maximum liklihood parameter estimation).
    """

    rangeChanged = pyqtSignal(str, int)
    updateProgress = pyqtSignal()
    processFinished = pyqtSignal()
    samplingFinished = pyqtSignal()
    finished = pyqtSignal()
    logMessage = pyqtSignal(str)
    errorReport = pyqtSignal(str)

    def __init__(self, ns=0, logreg=None):

        QObject.__init__(self)

        if logreg:
            self.logreg = logreg
        else:
            self.logreg = MLR()

        self.state = None
        self.factors = None
        self.output = None
        self.mode = "All"
        self.samples = None
        self.catlist = None

        self.ns = ns            # Neighbourhood size of training rasters.
        self.data = None        # Training data
        self.maxiter = 100      # Maximum of fitting iterations

        self.sampler = None     # Sampler

        # Results of the LR prediction
        self.prediction = None  # Raster of the LR prediction results
        self.confidence = None  # Raster of the LR results confidence (1 = the maximum confidence, 0 = the least confidence)
        self.Kappa      = 0     # Kappa value
        self.pseudoR    = 0     # Pseudo R-squared (Count) (http://www.ats.ucla.edu/stat/mult_pkg/faq/general/Psuedo_RSquareds.htm)
        self.transitionPotentials = None # Dictionary of transition potencial maps: {category1: map1, category2: map2, ...}

    def getCoef(self):
        return self.logreg.get_weights().T

    def getConfidence(self):
        return self.confidence

    def getIntercept(self):
        return self.logreg.get_intercept()

    def getKappa(self):
        return self.Kappa

    def getStdErrIntercept(self):
        X = np.column_stack( (self.data['state'], self.data['factors']) )
        return self.logreg.get_stderr_intercept(X)

    def getStdErrWeights(self):
        X = np.column_stack( (self.data['state'], self.data['factors']) )
        return self.logreg.get_stderr_weights(X).T

    def get_PvalIntercept(self):
        X = np.column_stack( (self.data['state'], self.data['factors']) )
        return self.logreg.get_pval_intercept(X)

    def get_PvalWeights(self):
        X = np.column_stack( (self.data['state'], self.data['factors']) )
        return self.logreg.get_pval_weights(X).T

    def getPrediction(self, state, factors, calcTransitions=False):
        self._predict(state, factors, calcTransitions)
        return self.prediction

    def getPseudoR(self):
        return self.pseudoR

    def getTransitionPotentials(self):
        return self.transitionPotentials

    def _outputConfidence(self, input):
        '''
        Return confidence (difference between 2 biggest probabilities) of the LR output.
        1 = the maximum confidence, 0 = the least confidence
        '''
        out_scl = self.logreg.predict_proba(input)[0]
        # Calculate the confidence:
        out_scl.sort()
        return int(100 * (out_scl[-1] - out_scl[-2]) )

    def outputTransitions(self, input):
        '''
        Return transition potential of the outputs
        '''
        out_scl = self.logreg.predict_proba(input)[0]
        out_scl = [int(100 * x) for x in out_scl]
        result = {}
        for r, v in enumerate(out_scl):
            cat = self.catlist[r]
            result[cat] = v
        return result

    def _predict(self, state, factors, calcTransitions=False):
        '''
        Calculate output and confidence rasters using LR model and input rasters
        @param state            Raster of the current state (categories) values.
        @param factors          List of the factor rasters (predicting variables).
        '''
        try:
            self.rangeChanged.emit(self.tr("Initialize model %p%"), 1)
            geodata = state.getGeodata()
            rows, cols = geodata['ySize'], geodata['xSize']
            for r in factors:
                if not state.geoDataMatch(r):
                    raise LRError('Geometries of the input rasters are different!')

            self.transitionPotentials = None    # Reset tr.potentials if they exist

            # Normalize factors before prediction:
            for f in factors:
                f.normalize(mode = 'mean')

            predicted_band  = np.zeros([rows, cols], dtype=np.uint8)
            confidence_band = np.zeros([rows, cols], dtype=np.uint8)
            if calcTransitions:
                self.transitionPotentials = {}
                for cat in self.catlist:
                    self.transitionPotentials[cat] = np.zeros([rows, cols], dtype=np.uint8)

            self.sampler = Sampler(state, factors, ns=self.ns)
            mask = state.getBand(1).mask.copy()
            if mask.shape == ():
                mask = np.zeros([rows, cols], dtype=np.bool)
            self.updateProgress.emit()
            self.rangeChanged.emit(self.tr("Prediction %p%"), rows)
            for i in xrange(rows):
                for j in xrange(cols):
                    if not mask[i,j]:
                        input = self.sampler.get_inputs(state, i,j)
                        if input != None:
                            input = np.array([input])
                            out = self.logreg.predict(input)
                            predicted_band[i,j] = out
                            confidence = self._outputConfidence(input)
                            confidence_band[i, j] = confidence

                            if calcTransitions:
                                potentials = self.outputTransitions(input)
                                for cat in self.catlist:
                                    map = self.transitionPotentials[cat]
                                    map[i, j] = potentials[cat]
                        else: # Input sample is incomplete => mask this pixel
                            mask[i, j] = True
                self.updateProgress.emit()
            predicted_bands  = [np.ma.array(data = predicted_band,  mask = mask, dtype=np.uint8)]
            confidence_bands = [np.ma.array(data = confidence_band, mask = mask, dtype=np.uint8)]

            self.prediction = Raster()
            self.prediction.create(predicted_bands, geodata)
            self.confidence = Raster()
            self.confidence.create(confidence_bands, geodata)

            if calcTransitions:
                for cat in self.catlist:
                    band = [np.ma.array(data=self.transitionPotentials[cat], mask=mask, dtype=np.uint8)]
                    self.transitionPotentials[cat] = Raster()
                    self.transitionPotentials[cat].create(band, geodata)
        except MemoryError:
            self.errorReport.emit(self.tr("The system out of memory during LR prediction"))
            raise
        except:
            self.errorReport.emit(self.tr("An unknown error occurs during LR prediction"))
            raise
        finally:
            self.processFinished.emit()

    def __propagateSamplerSignals(self):
        self.sampler.rangeChanged.connect(self.__samplerProgressRangeChanged)
        self.sampler.updateProgress.connect(self.__samplerProgressChanged)
        self.sampler.samplingFinished.connect(self.__samplerFinished)

    def __samplerFinished(self):
        self.sampler.rangeChanged.disconnect(self.__samplerProgressRangeChanged)
        self.sampler.updateProgress.disconnect(self.__samplerProgressChanged)
        self.sampler.samplingFinished.disconnect(self.__samplerFinished)
        self.samplingFinished.emit()

    def __samplerProgressRangeChanged(self, message, maxValue):
        self.rangeChanged.emit(message, maxValue)

    def __samplerProgressChanged(self):
        self.updateProgress.emit()

    def save(self):
        pass

    def saveSamples(self, fileName):
        self.sampler.saveSamples(fileName)

    def setMaxIter(self, maxiter):
        self.maxiter = maxiter

    def setTrainingData(self):
        state, factors, output, mode, samples = self.state, self.factors, self.output, self.mode, self.samples
        if not self.logreg:
            raise LRError('You must create a Logistic Regression model before!')

        # Normalize factors before sampling:
        for f in factors:
            f.normalize(mode = 'mean')

        self.sampler = Sampler(state, factors, output, ns=self.ns)
        self.__propagateSamplerSignals()
        self.sampler.setTrainingData(state, output, shuffle=False, mode=mode, samples=samples)

        outputVecLen  = self.sampler.outputVecLen
        stateVecLen   = self.sampler.stateVecLen
        factorVectLen = self.sampler.factorVectLen
        size = len(self.sampler.data)

        self.data = self.sampler.data
        self.catlist = np.unique(self.data['output'])

    def train(self):
        X = np.column_stack( (self.data['state'], self.data['factors']) )
        Y = self.data['output']
        self.labelCodes = np.unique(Y)
        self.logreg.fit(X, Y, maxiter=self.maxiter)
        out = self.logreg.predict(X)
        depCoef = DependenceCoef(np.ma.array(out), np.ma.array(Y), expand=True)
        self.Kappa = depCoef.kappa(mode=None)
        self.pseudoR = depCoef.correctness(percent = False)

    def setState(self, state):
        self.state = state

    def setFactors(self, factors):
        self.factors = factors

    def setOutput(self, output):
        self.output = output

    def setMode(self, mode):
        self.mode = mode

    def setSamples(self, samples):
        self.samples = samples

    def startTrain(self):
        try:
            self.setTrainingData()
            self.train()
        except MemoryError:
            self.errorReport.emit(self.tr("The system out of memory during LR training"))
            raise
        except:
            self.errorReport.emit(self.tr("An unknown error occurs during LR trainig"))
            raise
        finally:
            self.finished.emit()
Exemple #8
0
    def _predict(self, state, factors, calcTransitions=False):
        '''
        Calculate output and confidence rasters using LR model and input rasters
        @param state            Raster of the current state (categories) values.
        @param factors          List of the factor rasters (predicting variables).
        '''
        try:
            self.rangeChanged.emit(self.tr("Initialize model %p%"), 1)
            geodata = state.getGeodata()
            rows, cols = geodata['ySize'], geodata['xSize']
            for r in factors:
                if not state.geoDataMatch(r):
                    raise LRError('Geometries of the input rasters are different!')

            self.transitionPotentials = None    # Reset tr.potentials if they exist

            # Normalize factors before prediction:
            for f in factors:
                f.normalize(mode = 'mean')

            predicted_band  = np.zeros([rows, cols], dtype=np.uint8)
            confidence_band = np.zeros([rows, cols], dtype=np.uint8)
            if calcTransitions:
                self.transitionPotentials = {}
                for cat in self.catlist:
                    self.transitionPotentials[cat] = np.zeros([rows, cols], dtype=np.uint8)

            self.sampler = Sampler(state, factors, ns=self.ns)
            mask = state.getBand(1).mask.copy()
            if mask.shape == ():
                mask = np.zeros([rows, cols], dtype=np.bool)
            self.updateProgress.emit()
            self.rangeChanged.emit(self.tr("Prediction %p%"), rows)
            for i in xrange(rows):
                for j in xrange(cols):
                    if not mask[i,j]:
                        input = self.sampler.get_inputs(state, i,j)
                        if input != None:
                            input = np.array([input])
                            out = self.logreg.predict(input)
                            predicted_band[i,j] = out
                            confidence = self._outputConfidence(input)
                            confidence_band[i, j] = confidence

                            if calcTransitions:
                                potentials = self.outputTransitions(input)
                                for cat in self.catlist:
                                    map = self.transitionPotentials[cat]
                                    map[i, j] = potentials[cat]
                        else: # Input sample is incomplete => mask this pixel
                            mask[i, j] = True
                self.updateProgress.emit()
            predicted_bands  = [np.ma.array(data = predicted_band,  mask = mask, dtype=np.uint8)]
            confidence_bands = [np.ma.array(data = confidence_band, mask = mask, dtype=np.uint8)]

            self.prediction = Raster()
            self.prediction.create(predicted_bands, geodata)
            self.confidence = Raster()
            self.confidence.create(confidence_bands, geodata)

            if calcTransitions:
                for cat in self.catlist:
                    band = [np.ma.array(data=self.transitionPotentials[cat], mask=mask, dtype=np.uint8)]
                    self.transitionPotentials[cat] = Raster()
                    self.transitionPotentials[cat].create(band, geodata)
        except MemoryError:
            self.errorReport.emit(self.tr("The system out of memory during LR prediction"))
            raise
        except:
            self.errorReport.emit(self.tr("An unknown error occurs during LR prediction"))
            raise
        finally:
            self.processFinished.emit()