Example #1
0
    def analyze(self, output_dir):
        logging.info('Analyzing value...')

        # gets mean values and outliers
        self.values = np.array([datapoint.value for datapoint in self.data])
        self.value_mean = np.mean(self.values, axis=0)
        self.value_std = np.std(self.values, axis=0)
        all_outliers = set(
            get_outliers_dist_mean(self.values, self.config.value_outlier_stds,
                                   True, True))

        # registers outliers
        self.low_values = []
        self.high_values = []
        for t in range(1, len(self.data) - 1):
            # tests for above outlier
            if t in all_outliers and self.values[t] > self.value_mean and \
                    self.values[t - 1] <= self.values[t] > self.values[t + 1]:
                self.high_values.append(t)
            # tests for below outlier
            elif t in all_outliers and self.values[t] < self.value_mean and \
                    self.values[t - 1] >= self.values[t] < self.values[t + 1]:
                self.low_values.append(t)

        # sorts outliers
        self.high_values.sort(key=lambda i: self.values[i], reverse=True)
        self.low_values.sort(key=lambda i: self.values[i])

        # summary of elements
        logging.info('Finished')
        logging.info(f'\tMean value received over {len(self.data)} timesteps: '
                     f'{self.value_mean:.3f} ± {self.value_std:.3f}')
        logging.info('\tFound {} high values (stds={}): {}'.format(
            len(self.high_values), self.config.value_outlier_stds,
            self.high_values))
        logging.info('\tFound {} low values (stds={}): {}'.format(
            len(self.low_values), self.config.value_outlier_stds,
            self.low_values))

        logging.info('Saving report in {}...'.format(output_dir))

        # saves analysis report
        self.save(os.path.join(output_dir, 'value.pkl.gz'))

        value_std = self.values.std(0)
        self._save_time_dataset_csv(
            self.values, 'Value', os.path.join(output_dir, 'values-time.csv'))
        self._plot_elements_sp(
            self.values,
            self.value_mean + self.config.value_outlier_stds * value_std,
            self.value_mean - self.config.value_outlier_stds * value_std,
            os.path.join(output_dir, 'value-time.{}'.format(self.img_fmt)),
            'High value threshold', 'Low value threshold', 'Value', 'Value')

        save_list_csv(self.low_values,
                      os.path.join(output_dir, 'low-values.csv'))
        save_list_csv(self.high_values,
                      os.path.join(output_dir, 'high-values.csv'))
Example #2
0
    def analyze(self, output_dir):
        logging.info('Analyzing reward...')

        # gets mean rewards and outliers
        self.all_rewards = np.array(
            [datapoint.reward for datapoint in self.data])
        self.mean_reward = self.all_rewards.mean(0)
        all_outliers = set(
            get_outliers_dist_mean(self.all_rewards,
                                   self.config.rwd_outlier_stds, True, True))

        # registers outliers
        self.low_rewards = []
        self.high_rewards = []
        for t in range(1, len(self.data) - 1):
            # tests for above outlier
            if t in all_outliers and self.all_rewards[t] > self.mean_reward and \
                    self.all_rewards[t - 1] <= self.all_rewards[t] > self.all_rewards[t + 1]:
                self.high_rewards.append(t)
            # tests for below outlier
            elif t in all_outliers and self.all_rewards[t] < self.mean_reward and \
                    self.all_rewards[t - 1] >= self.all_rewards[t] < self.all_rewards[t + 1]:
                self.low_rewards.append(t)

        # sorts outliers
        self.high_rewards.sort(key=lambda i: self.all_rewards[i], reverse=True)
        self.low_rewards.sort(key=lambda i: self.all_rewards[i])

        # summary of elements
        logging.info('Finished')
        logging.info('\tMean reward received over {} timesteps: {:.3f}'.format(
            len(self.data), self.mean_reward))
        logging.info('\tFound {} high rewards (stds={}): {}'.format(
            len(self.high_rewards), self.config.rwd_outlier_stds,
            self.high_rewards))
        logging.info('\tFound {} low rewards (stds={}): {}'.format(
            len(self.low_rewards), self.config.rwd_outlier_stds,
            self.low_rewards))

        logging.info('Saving report in {}...'.format(output_dir))

        # saves analysis report
        self.save(os.path.join(output_dir, 'reward.pkl.gz'))

        rwd_std = self.all_rewards.std(0)
        save_list_csv(list(self.all_rewards),
                      os.path.join(output_dir, 'all_rewards.csv'))
        self._plot_elements(
            self.all_rewards, self.high_rewards, self.low_rewards,
            self.mean_reward + self.config.rwd_outlier_stds * rwd_std,
            self.mean_reward - self.config.rwd_outlier_stds * rwd_std,
            os.path.join(output_dir, 'reward-time.{}'.format(self.img_fmt)),
            'High reward threshold', 'Low reward threshold', 'Reward',
            'Reward')

        save_list_csv(self.low_rewards,
                      os.path.join(output_dir, 'low_rewards.csv'))
        save_list_csv(self.high_rewards,
                      os.path.join(output_dir, 'high_rewards.csv'))
Example #3
0
    def analyze(self, output_dir):
        logging.info(
            'Analyzing action execution value (maximum minimum differences)...'
        )

        # prepares multiprocessing
        pool = self._get_mp_pool()

        # gets action-factor exec max differences for each timestep
        data = [datapoint.action_probs for datapoint in self.data]
        self.all_execution_diffs = np.array(
            pool.map(_get_action_max_differences, data))

        # registers mean max diff outliers
        self.mean_execution_diffs = self.all_execution_diffs.mean(axis=1)
        self.mean_execution_diff = self.mean_execution_diffs.mean(0)
        self.high_exec_differences = []
        for t in range(1, len(self.data) - 1):
            # tests for high difference element (local maximum)
            if self.mean_execution_diffs[t] >= self.config.uncertain_exec_min_div and \
                    self.mean_execution_diffs[t - 1] <= self.mean_execution_diffs[t] > self.mean_execution_diffs[t + 1]:
                self.high_exec_differences.append(t)

        # sorts outliers
        self.high_exec_differences.sort(
            key=lambda i: self.mean_execution_diffs[i], reverse=True)

        # gets mean action factor max execution difference
        self.mean_action_factor_diffs = self.all_execution_diffs.mean(axis=0)

        # summary of elements
        logging.info('Finished')
        logging.info(
            '\tMean action-execution differences (peak-to-peak) over {} timesteps: {:.3f}'
            .format(len(self.data), self.mean_execution_diff))
        logging.info(
            '\tFound {} high execution differences (min diff={}): {}'.format(
                len(self.high_exec_differences),
                self.config.uncertain_exec_min_div,
                self.high_exec_differences))

        logging.info('Saving report in {}...'.format(output_dir))

        # saves analysis report
        self.save(os.path.join(output_dir, 'execution-value.pkl.gz'))
        np.savetxt(os.path.join(output_dir, 'all-execution-diffs.csv'),
                   self.all_execution_diffs,
                   '%s',
                   ',',
                   comments='')

        save_list_csv(self.mean_execution_diffs,
                      os.path.join(output_dir, 'mean-exec-diff-time.csv'))
        self._plot_elements(
            self.mean_execution_diffs, self.high_exec_differences, [],
            self.config.certain_exec_max_div, np.nan,
            os.path.join(output_dir,
                         'mean-exec-diff-time.{}'.format(self.img_fmt)),
            'High exec. diff. threshold', '',
            'Action Execution Max. Difference', 'Max. Prob. Difference')

        save_list_csv(self.mean_action_factor_diffs,
                      os.path.join(output_dir, 'mean-action-diffs.csv'))
        self._plot_action_factor_divs(
            self.mean_action_factor_diffs,
            os.path.join(output_dir,
                         'mean-action-diffs.{}'.format(self.img_fmt)),
            'Mean Action-Factor Execution Diff', 'Max. Prob. Difference')

        save_list_csv(self.high_exec_differences,
                      os.path.join(output_dir, 'high-exec-differences.csv'))

        for t in self.high_exec_differences:
            self._plot_action_factor_divs(
                self.all_execution_diffs[t],
                os.path.join(
                    output_dir,
                    'high-exec-{}-action-diffs.{}'.format(t, self.img_fmt)),
                'Mean Action-Factor Execution Diff', 'Max. Prob. Difference')
Example #4
0
    def analyze(self, output_dir):
        if len(self.data) == 0 or self.data[0].next_obs is None:
            logging.info('Epistemic uncertainty: nothing to analyze, skipping')
            return

        logging.info(
            'Analyzing epistemic uncertainty via variance in models\' predictions...'
        )

        # gets mean prediction variance and outliers, where shape is (sample+mean+var (3), num_nets, obs_dim)
        next_obs = np.array(
            [datapoint.next_obs[MODEL_MEAN_IDX] for datapoint in self.data])
        self.all_pred_vars = np.mean(np.square(
            np.linalg.norm(np.swapaxes(next_obs, 0, 1) - next_obs.mean(axis=1),
                           axis=-1)),
                                     axis=0)
        self.mean_pred_var = self.all_pred_vars.mean(0)
        all_outliers = set(
            get_outliers_dist_mean(self.all_pred_vars,
                                   self.config.epistemic_outlier_stds, True,
                                   True))

        # registers outliers
        self.low_pred_vars = []
        self.high_pred_vars = []
        for t in range(1, len(self.data) - 1):
            # tests for above outlier
            if t in all_outliers and self.all_pred_vars[t] > self.mean_pred_var and \
                    self.all_pred_vars[t - 1] <= self.all_pred_vars[t] > self.all_pred_vars[t + 1]:
                self.high_pred_vars.append(t)
            # tests for below outlier
            elif t in all_outliers and self.all_pred_vars[t] < self.mean_pred_var and \
                    self.all_pred_vars[t - 1] >= self.all_pred_vars[t] < self.all_pred_vars[t + 1]:
                self.low_pred_vars.append(t)

        # sorts outliers
        self.high_pred_vars.sort(key=lambda i: self.all_pred_vars[i],
                                 reverse=True)
        self.low_pred_vars.sort(key=lambda i: self.all_pred_vars[i])

        # summary of elements
        logging.info('Finished')
        logging.info(
            '\tMean epistemic uncertainty over {} timesteps: {:.3f}'.format(
                len(self.data), self.mean_pred_var))
        logging.info(
            '\tFound {} situations with high epistemic uncertainty (stds={}): {}'
            .format(len(self.high_pred_vars),
                    self.config.epistemic_outlier_stds, self.high_pred_vars))
        logging.info(
            '\tFound {} situations with low epistemic uncertainty (stds={}): {}'
            .format(len(self.low_pred_vars),
                    self.config.epistemic_outlier_stds, self.low_pred_vars))

        logging.info('Saving report in {}...'.format(output_dir))

        # saves analysis report
        self.save(os.path.join(output_dir, 'epistemic-uncert-var.pkl.gz'))

        rwd_std = self.all_pred_vars.std(0)
        save_list_csv(list(self.all_pred_vars),
                      os.path.join(output_dir, 'all-epistemic-uncert-var.csv'))
        self._plot_elements(
            self.all_pred_vars, self.high_pred_vars, self.low_pred_vars,
            self.mean_pred_var + self.config.epistemic_outlier_stds * rwd_std,
            self.mean_pred_var - self.config.epistemic_outlier_stds * rwd_std,
            os.path.join(output_dir,
                         'epistemic-uncert-var-time.{}'.format(self.img_fmt)),
            'High epistemic uncert. threshold',
            'Low epistemic uncert. threshold', 'Epistemic Uncertainty',
            'Predictive Models\' Observation Variance')

        save_list_csv(self.low_pred_vars,
                      os.path.join(output_dir, 'low-epistemic-uncert-var.csv'))
        save_list_csv(
            self.high_pred_vars,
            os.path.join(output_dir, 'high-epistemic-uncert-var.csv'))
    def analyze(self, output_dir):
        logging.info('Analyzing maximum value difference...')

        # gets mean ptps and outliers
        self.all_action_diffs = np.array([
            np.mean([
                np.ptp(factor_values)
                for factor_values in datapoint.action_values
            ]) for datapoint in self.data
        ])
        self.mean_diff = self.all_action_diffs.mean(0)
        all_outliers = set(
            get_outliers_dist_mean(self.all_action_diffs,
                                   self.config.value_outlier_stds, True, True))

        # registers outliers
        self.low_action_diffs = []
        self.high_action_diffs = []
        for t in range(1, len(self.data) - 1):
            # tests for above outlier
            if t in all_outliers and self.all_action_diffs[t] > self.mean_diff and \
                    self.all_action_diffs[t - 1] <= self.all_action_diffs[t] > self.all_action_diffs[t + 1]:
                self.high_action_diffs.append(t)
            # tests for below outlier
            elif t in all_outliers and self.all_action_diffs[t] < self.mean_diff and \
                    self.all_action_diffs[t - 1] >= self.all_action_diffs[t] < self.all_action_diffs[t + 1]:
                self.low_action_diffs.append(t)

        # sorts outliers
        self.high_action_diffs.sort(key=lambda i: self.all_action_diffs[i],
                                    reverse=True)
        self.low_action_diffs.sort(key=lambda i: self.all_action_diffs[i])

        # summary of elements
        logging.info('Finished')
        logging.info(
            '\tMean max action-value difference over {} timesteps: {:.3f}'.
            format(len(self.data), self.mean_diff))
        logging.info(
            '\tFound {} high action-value differences (stds={}): {}'.format(
                len(self.high_action_diffs), self.config.value_outlier_stds,
                self.high_action_diffs))
        logging.info(
            '\tFound {} low action-value differences (stds={}): {}'.format(
                len(self.low_action_diffs), self.config.value_outlier_stds,
                self.low_action_diffs))

        logging.info('Saving report in {}...'.format(output_dir))

        # saves analysis report
        self.save(os.path.join(output_dir, 'action-value.pkl.gz'))

        value_std = self.all_action_diffs.std(0)
        save_list_csv(list(self.all_action_diffs),
                      os.path.join(output_dir, 'all-action-diffs.csv'))
        self._plot_elements(
            self.all_action_diffs, self.high_action_diffs,
            self.low_action_diffs,
            self.mean_diff + self.config.value_outlier_stds * value_std,
            self.mean_diff - self.config.value_outlier_stds * value_std,
            os.path.join(output_dir,
                         'action-diff-time.{}'.format(self.img_fmt)),
            'High action-diff. threshold', 'Low action-diff. threshold',
            'Maximum Action-Value Difference', 'Action-Value Diff.')

        save_list_csv(self.low_action_diffs,
                      os.path.join(output_dir, 'low-action-diffs.csv'))
        save_list_csv(self.high_action_diffs,
                      os.path.join(output_dir, 'high-action-diffs.csv'))
    def analyze(self, output_dir):
        if len(self.data) == 0 or self.data[0].next_obs is None:
            logging.info('Epistemic uncertainty: nothing to analyze, skipping')
            return

        logging.info(
            'Analyzing epistemic uncertainty via JRD in models\' prob. predictions...'
        )

        # gets mean prediction JRD and outliers, where next_obs shape is (sample+mean+var (3), num_nets, obs_dim)

        # based on https://github.com/nnaisense/MAX/blob/master/utilities.py
        # shape: (steps, ensemble_size, d_state)
        mu = np.array(
            [datapoint.next_obs[MODEL_MEAN_IDX] for datapoint in self.data],
            dtype=np.double)
        var = np.array([
            datapoint.next_obs[MODEL_VARIANCE_IDX] for datapoint in self.data
        ],
                       dtype=np.double)
        steps, es, d_s = mu.shape

        # entropy of the mean
        entropy_mean = np.zeros(steps, dtype=np.double)
        for i in range(es):
            for j in range(es):
                mu_i, mu_j = mu[:, i], mu[:, j]  # shape: both (steps, d_state)
                var_i, var_j = var[:,
                                   i], var[:,
                                           j]  # shape: both (steps, d_state)

                mu_diff = mu_j - mu_i  # shape: (steps, d_state)
                var_sum = var_i + var_j  # shape: (steps, d_state)

                pre_exp = (mu_diff * 1 / var_sum * mu_diff
                           )  # shape: (steps, d_state)
                pre_exp = np.sum(pre_exp, axis=-1)  # shape: (steps)
                exp = np.exp(-1 / 2 * pre_exp)  # shape: (steps)

                den = np.sqrt(np.prod(var_sum, axis=-1))  # shape: (steps)

                entropy_mean += exp / den  # shape: (steps)

        entropy_mean = -np.log(entropy_mean / (((2 * np.pi)**(d_s / 2)) *
                                               (es * es)))  # shape: (steps)

        # mean of entropies
        total_entropy = np.prod(var, axis=-1)  # shape: (steps, ensemble_size)
        total_entropy = np.log(((2 * np.pi)**d_s) *
                               total_entropy)  # shape: (steps, ensemble_size)
        total_entropy = 1 / 2 * total_entropy + (d_s / 2) * np.log(
            2)  # shape: (steps, ensemble_size)
        mean_entropy = total_entropy.mean(axis=1)

        # Jensen-Renyi divergence
        self.all_pred_jrds = entropy_mean - mean_entropy  # shape: (steps)

        self.mean_pred_jrd = self.all_pred_jrds.mean(0)
        all_outliers = set(
            get_outliers_dist_mean(self.all_pred_jrds,
                                   self.config.epistemic_outlier_stds, True,
                                   True))

        # registers outliers
        self.low_pred_jrds = []
        self.high_pred_jrds = []
        for t in range(1, len(self.data) - 1):
            # tests for above outlier
            if t in all_outliers and self.all_pred_jrds[t] > self.mean_pred_jrd and \
                    self.all_pred_jrds[t - 1] <= self.all_pred_jrds[t] > self.all_pred_jrds[t + 1]:
                self.high_pred_jrds.append(t)
            # tests for below outlier
            elif t in all_outliers and self.all_pred_jrds[t] < self.mean_pred_jrd and \
                    self.all_pred_jrds[t - 1] >= self.all_pred_jrds[t] < self.all_pred_jrds[t + 1]:
                self.low_pred_jrds.append(t)

        # sorts outliers
        self.high_pred_jrds.sort(key=lambda i: self.all_pred_jrds[i],
                                 reverse=True)
        self.low_pred_jrds.sort(key=lambda i: self.all_pred_jrds[i])

        # summary of elements
        logging.info('Finished')
        logging.info(
            '\tMean epistemic uncertainty over {} timesteps: {:.3f}'.format(
                len(self.data), self.mean_pred_jrd))
        logging.info(
            '\tFound {} situations with high epistemic uncertainty (stds={}): {}'
            .format(len(self.high_pred_jrds),
                    self.config.epistemic_outlier_stds, self.high_pred_jrds))
        logging.info(
            '\tFound {} situations with low epistemic uncertainty (stds={}): {}'
            .format(len(self.low_pred_jrds),
                    self.config.epistemic_outlier_stds, self.low_pred_jrds))

        logging.info('Saving report in {}...'.format(output_dir))

        # saves analysis report
        self.save(os.path.join(output_dir, 'epistemic-uncert-jrd.pkl.gz'))

        rwd_std = self.all_pred_jrds.std(0)
        save_list_csv(list(self.all_pred_jrds),
                      os.path.join(output_dir, 'all-epistemic-uncert-jrd.csv'))
        self._plot_elements(
            self.all_pred_jrds, self.high_pred_jrds, self.low_pred_jrds,
            self.mean_pred_jrd + self.config.epistemic_outlier_stds * rwd_std,
            self.mean_pred_jrd - self.config.epistemic_outlier_stds * rwd_std,
            os.path.join(output_dir,
                         'epistemic-uncert-jrd-time.{}'.format(self.img_fmt)),
            'High epistemic uncert. threshold',
            'Low epistemic uncert. threshold', 'Epistemic Uncertainty',
            'Predictive Models\' Observation JRD')

        save_list_csv(self.low_pred_jrds,
                      os.path.join(output_dir, 'low-epistemic-uncert-jrd.csv'))
        save_list_csv(
            self.high_pred_jrds,
            os.path.join(output_dir, 'high-epistemic-uncert-jrd.csv'))
Example #7
0
    def analyze(self, output_dir):
        logging.info('Analyzing action execution uncertainty...')

        # prepares multiprocessing
        pool = self._get_mp_pool()

        # gets action-factor exec diversities for each timestep
        data = [datapoint.action_probs for datapoint in self.data]
        self.all_execution_divs = np.array(
            pool.map(_get_action_dist_evenness, data))

        # registers mean exec outliers
        self.mean_execution_divs = self.all_execution_divs.mean(axis=1)
        self.mean_execution_div = self.mean_execution_divs.mean(0)
        self.uncertain_executions = []
        self.certain_executions = []
        for t in range(1, len(self.data) - 1):
            # tests for uncertain element (local maximum)
            if self.mean_execution_divs[t] >= self.config.uncertain_exec_min_div and \
                    self.mean_execution_divs[t - 1] <= self.mean_execution_divs[t] > self.mean_execution_divs[t + 1]:
                self.uncertain_executions.append(t)
            # tests for certain element (local minimum)
            elif self.mean_execution_divs[t] <= self.config.certain_exec_max_div and \
                    self.mean_execution_divs[t - 1] >= self.mean_execution_divs[t] < self.mean_execution_divs[t + 1]:
                self.certain_executions.append(t)

        # sorts outliers
        self.uncertain_executions.sort(
            key=lambda i: self.mean_execution_divs[i], reverse=True)
        self.certain_executions.sort(key=lambda i: self.mean_execution_divs[i])

        # gets mean action factor execution diversity
        self.mean_action_factor_divs = self.all_execution_divs.mean(axis=0)

        # summary of elements
        logging.info('Finished')
        logging.info(
            '\tMean action-execution certainty over {} timesteps: {:.3f}'.
            format(len(self.data), self.mean_execution_div))
        logging.info(
            '\tFound {} uncertain action executions (min div={}): {}'.format(
                len(self.uncertain_executions),
                self.config.uncertain_exec_min_div, self.uncertain_executions))
        logging.info(
            '\tFound {} certain action executions (max div={}): {}'.format(
                len(self.certain_executions), self.config.certain_exec_max_div,
                self.certain_executions))

        logging.info('Saving report in {}...'.format(output_dir))

        # saves analysis report
        self.save(os.path.join(output_dir, 'execution-certainty.pkl.gz'))
        np.savetxt(os.path.join(output_dir, 'all-execution-divs.csv'),
                   self.all_execution_divs,
                   '%s',
                   ',',
                   comments='')

        self._save_time_dataset_csv(
            self.mean_execution_divs, 'Execution Uncertainty',
            os.path.join(output_dir, 'mean-exec-div-time.csv'))
        self._plot_elements_sp(
            self.mean_execution_divs, self.config.uncertain_exec_min_div,
            self.config.certain_exec_max_div,
            os.path.join(output_dir,
                         'mean-exec-div-time.{}'.format(self.img_fmt)),
            'Uncert. exec. threshold', 'Cert. exec. threshold',
            'Action Execution Uncertainty', 'Norm. True Diversity')

        save_list_csv(self.mean_action_factor_divs,
                      os.path.join(output_dir, 'mean-action-divs.csv'))
        self._plot_action_factor_divs(
            self.mean_action_factor_divs,
            os.path.join(output_dir,
                         'mean-action-divs.{}'.format(self.img_fmt)),
            'Mean Action-Factor Execution Uncertainty', 'Norm. True Diversity')

        save_list_csv(self.certain_executions,
                      os.path.join(output_dir, 'certain-executions.csv'))
        save_list_csv(self.uncertain_executions,
                      os.path.join(output_dir, 'uncertain-executions.csv'))

        for t in self.certain_executions:
            self._plot_action_factor_divs(
                self.all_execution_divs[t],
                os.path.join(
                    output_dir,
                    'cert-exec-{}-action-divs.{}'.format(t, self.img_fmt)),
                'Mean Action-Factor Execution Uncertainty',
                'Norm. True Diversity')
        for t in self.uncertain_executions:
            self._plot_action_factor_divs(
                self.all_execution_divs[t],
                os.path.join(
                    output_dir,
                    'uncert-exec-{}-action-divs.{}'.format(t, self.img_fmt)),
                'Mean Action-Factor Execution Uncertainty',
                'Norm. True Diversity')
Example #8
0
    def analyze(self, output_dir):
        if len(self.data) == 0 or self.data[0].next_obs is None:
            logging.info('Aleatoric uncertainty: nothing to analyze, skipping')
            return

        logging.info('Analyzing aleatoric uncertainty...')

        # gets mean prediction variance and outliers, where next_obs shape is (sample+mean+var (3), num_nets, obs_dim)
        self.all_pred_vars = np.array([
            mean_entropy(datapoint.next_obs[MODEL_VARIANCE_IDX])
            for datapoint in self.data
        ])
        self.mean_pred_var = self.all_pred_vars.mean(0)
        all_outliers = set(
            get_outliers_dist_mean(self.all_pred_vars,
                                   self.config.aleatoric_outlier_stds, True,
                                   True))

        # registers outliers
        self.low_pred_vars = []
        self.high_pred_vars = []
        for t in range(1, len(self.data) - 1):
            # tests for above outlier
            if t in all_outliers and self.all_pred_vars[t] > self.mean_pred_var and \
                    self.all_pred_vars[t - 1] <= self.all_pred_vars[t] > self.all_pred_vars[t + 1]:
                self.high_pred_vars.append(t)
            # tests for below outlier
            elif t in all_outliers and self.all_pred_vars[t] < self.mean_pred_var and \
                    self.all_pred_vars[t - 1] >= self.all_pred_vars[t] < self.all_pred_vars[t + 1]:
                self.low_pred_vars.append(t)

        # sorts outliers
        self.high_pred_vars.sort(key=lambda i: self.all_pred_vars[i],
                                 reverse=True)
        self.low_pred_vars.sort(key=lambda i: self.all_pred_vars[i])

        # summary of elements
        logging.info('Finished')
        logging.info(
            '\tMean aleatoric uncertainty over {} timesteps: {:.3f}'.format(
                len(self.data), self.mean_pred_var))
        logging.info(
            '\tFound {} situations with high aleatoric uncertainty (stds={}): {}'
            .format(len(self.high_pred_vars),
                    self.config.aleatoric_outlier_stds, self.high_pred_vars))
        logging.info(
            '\tFound {} situations with low aleatoric uncertainty (stds={}): {}'
            .format(len(self.low_pred_vars),
                    self.config.aleatoric_outlier_stds, self.low_pred_vars))

        logging.info('Saving report in {}...'.format(output_dir))

        # saves analysis report
        self.save(os.path.join(output_dir, 'aleatoric-uncertainty.pkl.gz'))

        rwd_std = self.all_pred_vars.std(0)
        save_list_csv(list(self.all_pred_vars),
                      os.path.join(output_dir, 'all-aleatoric-uncert.csv'))
        self._plot_elements(
            self.all_pred_vars, self.high_pred_vars, self.low_pred_vars,
            self.mean_pred_var + self.config.aleatoric_outlier_stds * rwd_std,
            self.mean_pred_var - self.config.aleatoric_outlier_stds * rwd_std,
            os.path.join(output_dir,
                         'aleatoric-uncert-time.{}'.format(self.img_fmt)),
            'High aleatoric uncert. threshold',
            'Low aleatoric uncert. threshold', 'Aleatoric Uncertainty',
            'Mean Prediction Variance')

        save_list_csv(self.low_pred_vars,
                      os.path.join(output_dir, 'low-aleatoric-uncert.csv'))
        save_list_csv(self.high_pred_vars,
                      os.path.join(output_dir, 'high-aleatoric-uncert.csv'))