Ejemplo n.º 1
0
class BootstrapRunner(AbstractRunner):
    def __init__(self, runnerArgument):
        """
        Parameters
        ----------
        runnerArgument: RunnerArgument

        Notes
        -----
        1. Uses METHOD_LEASTSQ for fitModel iterations.
        """
        super().__init__()
        #
        self.lastErr = ""
        self.fitter = runnerArgument.fitter
        self.numIteration = runnerArgument.numIteration
        self.kwargs = runnerArgument.kwargs
        self.synthesizerClass = runnerArgument.synthesizerClass
        if "logger" in self.fitter.__dict__.keys():
            self.logger = self.fitter.logger
        else:
            self.logger = Logger()
        self._isDone = not self._fitInitial()
        self.columns = self.fitter.selectedColumns
        # Initializations for bootstrap loop
        if not self.isDone:
            fittedTS = self.fitter.fittedTS.subsetColumns(self.columns,
                                                          isCopy=False)
            self.synthesizer = self.synthesizerClass(
                observedTS=self.fitter.observedTS.subsetColumns(self.columns,
                                                                isCopy=False),
                fittedTS=fittedTS,
                **self.kwargs)
            self.numSuccessIteration = 0
            if self.fitter.minimizerResult is None:
                self.fitter.fitModel()
            self.baseChisq = self.fitter.minimizerResult.redchi
            self.curIteration = 0
            self.fd = self.logger.getFileDescriptor()
            self.baseFittedStatistic = TimeseriesStatistic(
                self.fitter.observedTS.subsetColumns(
                    self.fitter.selectedColumns, isCopy=False))

    def report(self, id=None):
        if True:
            return
        if id is None:
            self._startTime = time.time()
        else:
            elapsed = time.time() - self._startTime
            print("%s: %2.3f" % (id, elapsed))

    @property
    def numWorkUnit(self):
        return self.numIteration

    @property
    def isDone(self):
        return self._isDone

    def run(self):
        """
        Runs the bootstrap.

        Returns
        -------
        BootstrapResult
        """
        def mkNullResult():
            fittedStatistic = TimeseriesStatistic(
                self.fitter.observedTS[self.fitter.selectedColumns])
            return BootstrapResult(self.fitter, 0, {}, fittedStatistic)

        #
        if self.isDone:
            return
        # Set up logging for this run
        if self.fd is not None:
            sys.stderr = self.fd
            sys.stdout = self.fd
        isSuccess = False
        bootstrapError = 0
        self.report()
        for _ in range(ITERATION_MULTIPLIER):
            newObservedTS = self.synthesizer.calculate()
            self.report("newObservedTS")
            # Update fitter to use the new observed data
            _ = self.fitter._updateObservedTS(newObservedTS, isCheck=False)
            self.report("updated fitter")
            # Try fitting
            try:
                self.fitter.fitModel(params=self.fitter.params)
                self.report("fitter.fit")
            except Exception as err:
                # Problem with the fit.
                msg = "modelFitterBootstrap. Fit failed on iteration %d."  \
                      % iteration
                self.logger.error(msg, err)
                bootstrapError += 1
                continue
            # Verify that there is a result
            if self.fitter.minimizerResult is None:
                continue
            # Check if the fit is of sufficient quality
            if self.fitter.minimizerResult.redchi > MAX_CHISQ_MULT * self.baseChisq:
                continue
            if self.fitter.params is None:
                continue
            isSuccess = True
            self.report("break")
            break
        # Create the result
        if isSuccess:
            self.numSuccessIteration += 1
            parameterDct = {
                k: [v]
                for k, v in self.fitter.params.valuesdict().items()
            }
            fittedStatistic = self.baseFittedStatistic.copy()
            fittedStatistic.accumulate(
                self.fitter.fittedTS.subsetColumns(self.fitter.selectedColumns,
                                                   isCopy=False))
            bootstrapResult = BootstrapResult(self.fitter,
                                              self.numSuccessIteration,
                                              parameterDct,
                                              fittedStatistic,
                                              bootstrapError=bootstrapError)
        else:
            bootstrapResult = mkNullResult()
            self._isDone = True
        # Close the logging file
        if self.fd is not None:
            if not self.fd.closed:
                self.fd.close()
        # See if completed work
        if self.numSuccessIteration >= self.numIteration:
            self._isDone = True
        return bootstrapResult

    def _fitInitial(self):
        """
        Do the initial fit.

        Returns
        -------
        bool
            successful fit
        """
        isSuccess = False
        for _ in range(MAX_TRIES):
            try:
                self.fitter.fitModel()  # Initialize model
                isSuccess = True
                break
            except Exception as err:
                self.lastErr = err
                msg = "Could not do initial fit"
                self.logger.error(msg, err)
        return isSuccess
Ejemplo n.º 2
0
class TestNamedTimeseries(unittest.TestCase):
    def setUp(self):
        self.timeseries = SIMPLE_TS
        self.statistic = TimeseriesStatistic(self.timeseries)

    def testConstructor(self):
        if IGNORE_TEST:
            return
        colnames = list(COLNAMES)
        colnames.remove(TIME)
        diff = set(self.statistic.colnames).symmetric_difference(colnames)
        self.assertEqual(len(diff), 0)

    def testAccumulate(self):
        if IGNORE_TEST:
            return
        self.statistic.accumulate(SIMPLE_TS)
        self.assertTrue(self.statistic.sumTS.equals(SIMPLE_TS))

    def testCalculate1(self):
        if IGNORE_TEST:
            return
        for _ in range(SIMPLE_CNT):
            self.statistic.accumulate(SIMPLE_TS)
        self.statistic.calculate()
        self.assertEqual(self.statistic.count, SIMPLE_CNT)
        self.assertTrue(self.statistic.meanTS.equals(SIMPLE_TS))
        stdTS = SIMPLE_TS.copy(isInitialize=True)
        self.assertTrue(self.statistic.stdTS.equals(stdTS))

    def mkStatistics(self, count):
        result = []
        for _ in range(count):
            statistic = TimeseriesStatistic(UNIFORM_TS)
            for _ in range(UNIFORM_CNT):
                statistic.accumulate(
                    mkTimeseries(UNIFORM_LEN, COLNAMES, isRandom=True))
            result.append(statistic)
        return result

    def evaluateStatistic(self, statistic, count=1):
        statistic.calculate()
        self.assertEqual(statistic.count, count * UNIFORM_CNT)
        mean = np.mean(statistic.meanTS.flatten())
        self.assertLess(np.abs(mean - UNIFORM_MEAN), 0.1)
        std = np.mean(statistic.stdTS.flatten())
        self.assertLess(np.abs(std - UNIFORM_STD), 0.1)
        for percentile in self.statistic.percentiles:
            value = np.mean(statistic.percentileDct[percentile].flatten())
            self.assertLess(np.abs(value - 0.01 * percentile), 0.01)

    def testCalculate2(self):
        if IGNORE_TEST:
            return
        statistic = self.mkStatistics(1)[0]
        self.evaluateStatistic(statistic)

    def testEquals(self):
        if IGNORE_TEST:
            return
        statistic = TimeseriesStatistic(self.timeseries)
        self.assertTrue(self.statistic.equals(statistic))
        #
        statistic.accumulate(SIMPLE_TS)
        self.assertFalse(self.statistic.equals(statistic))

    def testCopy(self):
        if IGNORE_TEST:
            return
        statistic = self.statistic.copy()
        self.assertTrue(self.statistic.equals(statistic))
        #
        statistic = self.mkStatistics(1)[0]
        self.assertTrue(statistic.equals(statistic))

    def testMerge(self):
        if IGNORE_TEST:
            return
        NUM = 4
        statistics = self.mkStatistics(NUM)
        statistic = TimeseriesStatistic.merge(statistics)
        statistic.calculate()
        self.evaluateStatistic(statistic, count=NUM)

    def testRpickleInterface(self):
        if IGNORE_TEST:
            return
        serialization = rpickle.Serialization(self.statistic)
        statistic = serialization.deserialize()
        self.assertTrue(statistic.meanTS.equals(self.statistic.meanTS))