easyvvuq.analysis.results

Represents the results obtained during the analysis stage. All the analysis classes should implement this in a way that makes most sense. Provides a more unified interface for accessing the results in a variety of formats (e.g. NumPy arrays or pandas DataFrames). This module also provides a variety of ways to display results as well as a way to access surrogate functionality.

  1"""
  2Represents the results obtained during the analysis stage.
  3All the analysis classes should implement this in a way that makes
  4most sense. Provides a more unified interface for accessing the results
  5in a variety of formats (e.g. NumPy arrays or pandas DataFrames). This module
  6also provides a variety of ways to display results as well as a way to access
  7surrogate functionality.
  8"""
  9
 10import pandas as pd
 11import numpy as np
 12import itertools
 13
 14
 15class AnalysisResults:
 16    """Contains the analysis results.
 17
 18    Parameters
 19    ----------
 20    raw_data: obj
 21        An arbitrary object that contains raw analysis data.
 22
 23    samples: pandas DataFrame
 24        Collated samples.
 25
 26    qois: list of str
 27        List of qoi names used during the analysis.
 28
 29    inputs: list of str
 30        List of input names used during the analysis.
 31    """
 32
 33    def __init__(self, raw_data=None, samples=None, qois=None, inputs=None):
 34        self.raw_data = raw_data
 35        self.samples = samples
 36        self.qois = qois
 37        self.inputs = inputs
 38
 39    def supported_stats(self):
 40        """Returns a list of descriptive statistics that the method reports.
 41
 42        Examples
 43        --------
 44        >>> results.supported_stats()
 45        ['min', 'max', '10%', '90%', '1%', '99%', 'median', 'mean', 'var', 'std']
 46
 47        Returns
 48        -------
 49        list of str
 50            A list of statistics that can then be passed to the `describe` method.
 51        """
 52        raise NotImplementedError('descriptive statistics not available in this method')
 53
 54    def _get_derivatives_first(self, qoi, input_):
 55        """Returns the first order derivative-based index for a given qoi wrt input variable.
 56
 57        Parameters
 58        ----------
 59        qoi : str
 60           Quantity of interest
 61        input_ : str
 62           Input variable
 63
 64        Returns
 65        -------
 66        float
 67            First order derivative-based index.
 68        """
 69        raise NotImplementedError
 70
 71
 72    def _get_sobols_first(self, qoi, input_):
 73        """Returns first order Sobol indices.
 74
 75        Parameters
 76        ----------
 77        qoi - str or tuple
 78            Quantity of interest or if a tuple quantity of interest plus
 79            coordinate index (for cases where qoi is vector valued).
 80        input_ - str
 81            Input variable name.
 82
 83        Returns
 84        -------
 85        np.array
 86            An array with first order sobol indices. If the `qoi` is not vector valued the
 87            array will have one element.
 88        """
 89        raise NotImplementedError
 90
 91    def _get_sobols_second(self, qoi, input_):
 92        """Returns second order Sobol indices.
 93
 94        Parameters
 95        ----------
 96        qoi - str or tuple
 97           Quantity of interest or if a tuple quantity of interest plus
 98           coordinate index (for cases where qoi is vector valued).
 99        input_ - str
100           Input variable name.
101
102        Returns
103        -------
104        np.array
105            An array with first order sobol indices. If the `qoi` is not vector valued the
106            array will have one element.
107        """
108        raise NotImplementedError
109
110    def _get_sobols_total(self, qoi, input_):
111        """Returns total order Sobol indices.
112
113        Parameters
114        ----------
115        qoi - str or tuple
116           Quantity of interest or if a tuple quantity of interest plus
117           coordinate index (for cases where qoi is vector valued).
118        input_ - str
119           Input variable name.
120
121        Returns
122        -------
123        np.array
124            An array with total order sobol indices. If the `qoi` is not vector valued the
125            array will have one element.
126        """
127        raise NotImplementedError
128
129    def _get_sobols_first_conf(self, qoi, input_):
130        """Returns confidence intervals for first order Sobol indices.
131
132        Attributes
133        ----------
134        qoi : str
135            Name of the qoi for which the first order sensitivity index
136            confidence interval is requested.
137        input_ : str
138            Name of the input for which the first order sensitivy index
139            confidence interval is requested.
140
141        Returns
142        -------
143        list
144            A list of two floats - lower and upper confidence interval bounds.
145        """
146        raise NotImplementedError
147
148    def _get_sobols_total_conf(self, qoi, input_):
149        """Returns confidence intervals for total order Sobol indices.
150
151        Attributes
152        ----------
153        qoi : str
154            Name of the qoi for which the first order sensitivity index
155            confidence interval is requested.
156        input_ : str
157            Name of the input for which the first order sensitivy index
158            confidence interval is requested.
159
160        Returns
161        -------
162        list
163            A list of two floats - lower and upper confidence interval bounds.
164        """
165        raise NotImplementedError
166
167    def _get_sobols_general(self, getter, qoi=None, input_=None):
168        """A generic method for getting sobol indices.
169
170        Parameters
171        ----------
172        getter: function
173             Method that takes a AnalysisResults instance and returns
174             a Sobol index of some kind. For example _get_bonols_first.
175
176        qoi: str or tuple
177            The name of the quantity of interest or None.
178            Use a tuple of the form (qoi, index) where index is integer
179            that means the coordinate index of a vector qoi.
180
181        input_: str
182            The name of the input parameter or None.
183
184        Returns
185        -------
186        dict or array
187        """
188        assert (not ((qoi is None) and (input_ is not None)))
189        if (qoi is not None) and (qoi not in self.qois):
190            raise RuntimeError('no such qoi in this analysis')
191        if (input_ is not None) and (input_ not in self.inputs):
192            raise RuntimeError('no such input variable in this analysis')
193        try:
194            if input_ is None:
195                if qoi is None:
196                    return dict([(qoi_, dict([(in_, getter(qoi_, in_))
197                                              for in_ in self.inputs]))
198                                 for qoi_ in self.qois])
199                else:
200                    return dict([(in_, getter(qoi, in_))
201                                 for in_ in self.inputs])
202            else:
203                return getter(qoi, input_)
204        except NotImplementedError:
205            raise RuntimeError(
206                'this kind of sobol index reporting not implemented in this analysis method')
207
208    def derivatives_first(self, qoi=None, input_=None):
209        """Return first order derivative-based sensitivity indices.
210
211        Parameters
212        ----------
213        qoi: str or tuple
214            The name of the quantity of interest or None.
215            Use a tuple of the form (qoi, index) where index is integer
216            that means the coordinate index of a vector qoi.
217
218        input_: str
219            The name of the input parameter or None.
220
221        Examples
222        --------
223        >>> results.derivatives_first()
224        {'f': {'x1': array([0.610242]), 'x2': array([0.26096511])}}
225        >>> results.derivatives_first('f')
226        {'x1': array([0.610242]), 'x2': array([0.26096511])}
227        >>> results.derivatives_first('f', 'x1')
228        array([0.610242])
229        >>> results_vectors.derivatives_first(('g', 2))
230        {'x1': array([0.5]), 'x2': array([0.5])}
231
232        Returns
233        -------
234        dict or array
235           If both qoi and input_ are specified will return a dictionary,
236           otherwise will return an array.
237        """
238        return self._get_sobols_general(self._get_derivatives_first, qoi, input_)
239
240    def sobols_first(self, qoi=None, input_=None):
241        """Return first order sensitivity indices.
242
243        Parameters
244        ----------
245        qoi: str or tuple
246            The name of the quantity of interest or None.
247            Use a tuple of the form (qoi, index) where index is integer
248            that means the coordinate index of a vector qoi.
249
250        input_: str
251            The name of the input parameter or None.
252
253        Examples
254        --------
255        >>> results.sobols_first()
256        {'f': {'x1': array([0.610242]), 'x2': array([0.26096511])}}
257        >>> results.sobols_first('f')
258        {'x1': array([0.610242]), 'x2': array([0.26096511])}
259        >>> results.sobols_first('f', 'x1')
260        array([0.610242])
261        >>> results_vectors.sobols_first(('g', 2))
262        {'x1': array([0.5]), 'x2': array([0.5])}
263
264        Returns
265        -------
266        dict or array
267           If both qoi and input_ are specified will return a dictionary,
268           otherwise will return an array.
269        """
270        return self._get_sobols_general(self._get_sobols_first, qoi, input_)
271
272    def sobols_second(self, qoi=None, input_=None):
273        """Return second order sensitivity indices.
274
275        Parameters
276        ----------
277        qoi: str or tuple
278            The name of the quantity of interest or None.
279            Use a tuple of the form (qoi, index) where index is integer
280            that means the coordinate index of a vector qoi.
281
282        input_: str
283            The name of the input parameter or None.
284
285        Examples
286        --------
287        >>> results.sobols_second('a')
288        {'F': {'L': array([0.000121]),
289        'a': array([0.00695338]),
290        'D': array([0.00141272])},
291        'L': {'F': array([0.000121]),
292        'a': array([0.00012737]),
293        'D': array([0.00012716])},
294        'a': {'F': array([0.00695338]),
295        'L': array([0.00012737]),
296        'D': array([0.00730415])},
297        'D': {'F': array([0.00141272]),
298        'L': array([0.00012716]),
299        'a': array([0.00730415])}}
300        >>> results.sobols_second('g1', 'L')
301        {'F': array([0.000121]), 'a': array([0.00012737]), 'D': array([0.00012716])}
302        Returns
303        -------
304        dict
305           Will always return a dictionary unlike first order sobol indices. Because
306           the index is specified by a pair of inputs. The dictionary will include
307           all inputs but `input_`.
308        """
309        return self._get_sobols_general(self._get_sobols_second, qoi, input_)
310
311    def sobols_total(self, qoi=None, input_=None):
312        """Returns total order sensitivity indices.
313
314        Parameters
315        ----------
316        qoi: str or tuple
317            The name of the quantity of interest or None.
318            Use a tuple of the form (qoi, index) where index is integer
319            that means the coordinate index of a vector qoi.
320        input_: str
321            The name of the input parameter or None.
322
323
324        Examples
325        --------
326        >>> results.sobols_total('g1')
327        {'F': array([0.14299044]),
328        'L': array([0.01247877]),
329        'a': array([0.7105291]),
330        'D': array([0.15018883])}
331        >>> results.sobols_total('g1', 'F')
332        array([0.14299044])
333
334        Returns
335        -------
336        dict or array
337           If both qoi and input_ are specified will return a dictionary,
338           otherwise will return an array.
339        """
340        return self._get_sobols_general(self._get_sobols_total, qoi, input_)
341
342    def surrogate(self):
343        """Returns the surrogate model as a function from parameter dictionary
344        to output dictionary. This only needs to be implemented if the analysis
345        method in question provides surrogate models.
346
347
348        Returns
349        -------
350        function
351            Returns a function that takes a dictionary and returns a dictionary.
352            These dictionaries use the same format as Encoder and Decoder used
353            to construct the surrogate.
354        """
355        raise NotImplementedError
356
357    def describe(self, qoi=None, statistic=None):
358        """Returns descriptive statistics.
359
360        Examples
361        --------
362        >>> results.describe()
363                     g                             h
364                     0         1         2         0         1
365        mean  0.500000  0.500000  1.000000  0.250000  0.693787
366        var   0.083333  0.083333  0.166667  0.048611  0.068236
367        std   0.288675  0.288675  0.408248  0.220479  0.261220
368        10%   0.100897  0.099462  0.441589  0.019049  0.276504
369        90%   0.896960  0.899417  1.544624  0.584600  0.974707
370        min   0.000041  0.000005  0.016687  0.000016 -0.008642
371        max   0.999998  0.999873  1.993517  0.985350  1.024599
372
373        >>> result.describe('h')
374                     h
375                     0         1
376        mean  0.250000  0.693787
377        var   0.048611  0.068236
378        std   0.220479  0.261220
379        10%   0.019049  0.276504
380        90%   0.584600  0.974707
381        min   0.000016 -0.008642
382        max   0.985350  1.024599
383
384        >>> results.describe('h', 'var')
385        array([0.04861111, 0.06823568])
386
387        Parameters
388        ----------
389        qoi: str or None
390            if not None it is the name of the quantity of interest
391        statistic: str or None
392            if not None it is the name of the statistic, currently supported ones
393            are: ['mean', 'var', 'std', '10%', '90%', 'min', 'max', 'median']
394
395        Returns
396        -------
397        DataFrame or array
398            If both quantity of interest and the statistic are specified will return
399            an array with the values for that statistic. Otherwise will return a DataFrame
400            with more data.
401        """
402        assert (not ((qoi is None) and (statistic is not None)))
403        statistics = ['mean', 'var', 'std', '1%', '10%', '90%', '99%', 'min', 'max', 'median']
404        qois = self.qois
405        if qoi is not None:
406            qois = [qoi]
407        if statistic is not None:
408            statistics = [statistic]
409        result = {}
410        for qoi in qois:
411            for statistic_ in statistics:
412                try:
413                    value = self._describe(qoi, statistic_)
414                    assert (isinstance(value, np.ndarray))
415                    for i, x in enumerate(value):
416                        try:
417                            result[(qoi, i)][statistic_] = x
418                        except KeyError:
419                            result[(qoi, i)] = {statistic_: x}
420                except NotImplementedError:
421                    if statistic is not None:
422                        raise RuntimeError(
423                            "this statistic ({}) is not reported by this analysis class".format(statistic))
424        if qois is not None and statistic is not None:
425            return pd.DataFrame(result)[qoi].loc[statistic].values
426        else:
427            return pd.DataFrame(result)
428
429    def plot_sobols_treemap(self, qoi, figsize=(10, 10), ax=None, filename=None, dpi=None):
430        """Plot sobols first and second order indices in a hierarchical treemap format.
431
432        Parameters
433        ----------
434        qoi: str
435           Name of the quantity of interest.
436        figsize: tuple
437           A tuple with two integers representing figure size in inches.
438        ax: matplotlib
439           Matplotlib axis to plot on.
440        filename: str
441           Filename to write the plot to. If left None will display to screen.
442        dpi: int
443           Dots per inches. Only used when writing to file.
444        """
445        if qoi not in self.qois:
446            raise RuntimeError("no such qoi - {}".format(qoi))
447        import matplotlib.pyplot as plt
448        import matplotlib._color_data as mcd
449        import squarify
450        sobols_first = self.sobols_first(qoi)
451        keys = list(sobols_first.keys())
452        values = [value[0] for value in list(sobols_first.values())]
453        keys = ["{}\n{:.5f}".format(key, value) for key, value in zip(keys, values)]
454        if sum(values) < 1.0:
455            keys.append("higher orders\n{:.5f}".format(1.0 - sum(values)))
456            values.append(1.0 - sum(values))
457        colors = mcd.XKCD_COLORS
458        if ax is None:
459            fig, ax = plt.subplots()
460        else:
461            fig = ax.get_figure()
462        fig.set_size_inches(figsize)
463        ax.set_title("Decomposition of {} variance".format(qoi))
464        squarify.plot(sizes=values, label=keys, color=colors, ax=ax, pad=True)
465        ax.axis('off')
466        if filename is None:
467            fig.show()
468        else:
469            fig.savefig(filename, dpi=dpi)
470
471    def plot_sobols_first(self, qoi, inputs=None, withdots=False,
472                          ylabel=None, xlabel=None, xvalues=None,
473                          filename=None, dpi=None, ax=None):
474        """Plot first order sobol indices.
475
476        Parameters
477        ----------
478        qoi: str
479            a vector quantity of interest for which sobol indices will be plotted
480        inputs: list of str or None
481            list of inputs to plot if None will use all input variables
482        withdots: bool
483            if True will add shapes on top of the lines in the plot for visual clarity
484        ylabel: str or None
485            if None will use "First Order Sobol Index"
486        xlabel: str or None
487            if None will use the name of the qoi
488        xvalues: array or None
489           x-axis coordiante if None will use range(len(qoi_values))
490        filename: str or None
491            if None will try to open a plotting window on-screen, otherwise will write the plot to this file, with the type determined by the extension specified
492        dpi: int
493            dots per inch, quality of the image if a raster format was chosen
494        ax: matplotlib axes object, default None
495            if None, plots to a new axes, otherwise plot to existing axes ax
496
497        Returns
498        -------
499        matplotlib axes object
500            the actual axes plotted to
501        """
502        if qoi not in self.qois:
503            raise RuntimeError("no such qoi - {}".format(qoi))
504        if inputs is None:
505            inputs = self.inputs
506        for input_ in inputs:
507            if input_ not in self.inputs:
508                raise RuntimeError("no such input variable - {}".format(input_))
509        import matplotlib.pyplot as plt
510        if withdots:
511            styles = itertools.cycle(['-o', '-v', '-^', '-<', '->', '-8', '-s',
512                                      '-p', '-*', '-h', '-H', '-D', '-d', '-P', '-X'])
513        else:
514            styles = itertools.cycle(['-'])
515        points = None
516        for input_ in inputs:
517            if points is None:
518                indices = self.sobols_first(qoi, input_)
519                if len(indices) < 2:
520                    raise RuntimeError('this method is only implemented for vector qois')
521                points = [indices]
522            else:
523                points.append(self.sobols_first(qoi, input_))
524        if xvalues is None:
525            xvalues = np.arange(len(points[0]))
526        if ax is None:
527            fig, ax = plt.subplots()
528        else:
529            fig = ax.get_figure()
530        higher = np.array([1.0] * len(points[0]))
531        for p, label in zip(points, inputs):
532            higher -= p
533            ax.plot(xvalues, p, next(styles), label=label)
534        ax.plot(xvalues, higher, next(styles), label='higher orders')
535        ax.grid(True)
536        if ylabel is None:
537            ax.set_ylabel('First Order Sobol Index')
538        else:
539            ax.set_ylabel(ylabel)
540        if xlabel is None:
541            ax.set_xlabel('x-axis')
542        else:
543            ax.set_xlabel(xlabel)
544        ax.legend()
545        if filename is not None:
546            fig.savefig(filename, dpi=dpi)
547        return ax
548
549    def plot_moments(
550            self,
551            qoi,
552            ylabel=None,
553            xlabel=None,
554            xvalues=None,
555            alpha=0.2,
556            filename=None,
557            dpi=None,
558            ax=None):
559        """Plot statistical moments for this analysis.
560
561        Parameters
562        ----------
563        qoi: str
564            a vector quantity of interest for which sobol indices will be plotted
565        ylabel: str or None
566            if None will use "Values"
567        xlabel: str or None
568            if None will use the name of the qoi
569        xvalues: array or None
570            x-axis coordiante if None will use range(len(qoi_values)))
571        alpha: float
572            transparency amount
573        filename: str or None
574            if None will try to open a plotting window on-screen, otherwise will
575            write the plot to this file, with the type determined by the extension specified
576        dpi: int
577            dots per inch, quality of the image if a raster format was chosen
578        ax: matplotlib axes object, default None
579            if None, plots to a new axes, otherwise plot to existing axes ax
580
581        Returns
582        -------
583        matplotlib axes object
584            the actual axes plotted to
585        """
586        if qoi not in self.qois:
587            raise RuntimeError("no such qoi - {}".format(qoi))
588        import matplotlib.pyplot as plt
589        if ax is None:
590            fig, ax = plt.subplots()
591        else:
592            fig = ax.get_figure()
593        if xvalues is None:
594            xvalues = np.arange(len(self.describe(qoi, 'mean')))
595        ax.fill_between(xvalues, self.describe(qoi, 'mean') -
596                        self.describe(qoi, 'std'), self.describe(qoi, 'mean') +
597                        self.describe(qoi, 'std'), label='std', alpha=alpha)
598        ax.plot(xvalues, self.describe(qoi, 'mean'), label='mean')
599        if all(v in self.supported_stats() for v in ['1%', '99%']):
600            ax.plot(xvalues, self.describe(qoi, '1%'), '--', label='1%', color='black')
601            ax.plot(xvalues, self.describe(qoi, '99%'), '--', label='99%', color='black')
602        ax.grid(True)
603        if ylabel is None:
604            ax.set_ylabel(qoi)
605        else:
606            ax.set_ylabel(ylabel)
607        if xlabel is None:
608            ax.set_xlabel('x-axis')
609        else:
610            ax.set_xlabel(xlabel)
611        ax.legend()
612        if filename is not None:
613            fig.savefig(filename, dpi=dpi)
614        return ax
615
616    def get_distribution(self, qoi):
617        """Returns a distribution for the given qoi.
618
619        Parameters
620        ----------
621        qoi: str
622            QoI name
623
624        Returns
625        -------
626        A ChaosPy distribution
627        """
628        raise NotImplementedError
629
630    @staticmethod
631    def _keys_to_tuples(dictionary):
632        """Convert the keys in the dictionary to tuples.
633
634        Parameters
635        ----------
636        dictionary : dict
637            A dictionary with either strings or tuples as keys.
638
639        Examples
640        --------
641        >>> AnalysisResults._keys_to_tuples({'a': 1, 'b': 2})
642        {('a', 0): 1, ('b', 0): 2})
643
644        >>> AnalysisResults._keys_to_tuples({('a', 0): 1, ('b', 0): 2})
645        {('a', 0): 1, ('b', 0): 2})
646
647        >>> AnalysisResults._keys_to_tuples({('a', 0): 1, 'b': 2})
648        {('a', 0): 1, ('b', 0): 2})
649
650        Returns
651        -------
652        A dictionary with tuples as keys.
653        """
654        new_dict = {}
655        for key in dictionary.keys():
656            new_dict[AnalysisResults._to_tuple(key)] = dictionary[key]
657        return new_dict
658
659    @staticmethod
660    def _to_tuple(key):
661        """Convert key to tuple if it is string, otherwise leave as is.
662
663        Parameters
664        ----------
665        key: str or tuple
666
667        Examples
668        --------
669        >>> AnalysisResults._to_tuple('a')
670        ('a', 0)
671
672        >>> AnalysisResults._to_tuple(('a', 0))
673        ('a', 0)
674
675        Returns
676        -------
677        Tuple if key is string, key if key is tuple.
678        """
679        if isinstance(key, tuple):
680            return key
681        elif isinstance(key, str):
682            return (key, 0)
683        else:
684            raise RuntimeError("this method expects either a string or tuple")
class AnalysisResults:
 16class AnalysisResults:
 17    """Contains the analysis results.
 18
 19    Parameters
 20    ----------
 21    raw_data: obj
 22        An arbitrary object that contains raw analysis data.
 23
 24    samples: pandas DataFrame
 25        Collated samples.
 26
 27    qois: list of str
 28        List of qoi names used during the analysis.
 29
 30    inputs: list of str
 31        List of input names used during the analysis.
 32    """
 33
 34    def __init__(self, raw_data=None, samples=None, qois=None, inputs=None):
 35        self.raw_data = raw_data
 36        self.samples = samples
 37        self.qois = qois
 38        self.inputs = inputs
 39
 40    def supported_stats(self):
 41        """Returns a list of descriptive statistics that the method reports.
 42
 43        Examples
 44        --------
 45        >>> results.supported_stats()
 46        ['min', 'max', '10%', '90%', '1%', '99%', 'median', 'mean', 'var', 'std']
 47
 48        Returns
 49        -------
 50        list of str
 51            A list of statistics that can then be passed to the `describe` method.
 52        """
 53        raise NotImplementedError('descriptive statistics not available in this method')
 54
 55    def _get_derivatives_first(self, qoi, input_):
 56        """Returns the first order derivative-based index for a given qoi wrt input variable.
 57
 58        Parameters
 59        ----------
 60        qoi : str
 61           Quantity of interest
 62        input_ : str
 63           Input variable
 64
 65        Returns
 66        -------
 67        float
 68            First order derivative-based index.
 69        """
 70        raise NotImplementedError
 71
 72
 73    def _get_sobols_first(self, qoi, input_):
 74        """Returns first order Sobol indices.
 75
 76        Parameters
 77        ----------
 78        qoi - str or tuple
 79            Quantity of interest or if a tuple quantity of interest plus
 80            coordinate index (for cases where qoi is vector valued).
 81        input_ - str
 82            Input variable name.
 83
 84        Returns
 85        -------
 86        np.array
 87            An array with first order sobol indices. If the `qoi` is not vector valued the
 88            array will have one element.
 89        """
 90        raise NotImplementedError
 91
 92    def _get_sobols_second(self, qoi, input_):
 93        """Returns second order Sobol indices.
 94
 95        Parameters
 96        ----------
 97        qoi - str or tuple
 98           Quantity of interest or if a tuple quantity of interest plus
 99           coordinate index (for cases where qoi is vector valued).
100        input_ - str
101           Input variable name.
102
103        Returns
104        -------
105        np.array
106            An array with first order sobol indices. If the `qoi` is not vector valued the
107            array will have one element.
108        """
109        raise NotImplementedError
110
111    def _get_sobols_total(self, qoi, input_):
112        """Returns total order Sobol indices.
113
114        Parameters
115        ----------
116        qoi - str or tuple
117           Quantity of interest or if a tuple quantity of interest plus
118           coordinate index (for cases where qoi is vector valued).
119        input_ - str
120           Input variable name.
121
122        Returns
123        -------
124        np.array
125            An array with total order sobol indices. If the `qoi` is not vector valued the
126            array will have one element.
127        """
128        raise NotImplementedError
129
130    def _get_sobols_first_conf(self, qoi, input_):
131        """Returns confidence intervals for first order Sobol indices.
132
133        Attributes
134        ----------
135        qoi : str
136            Name of the qoi for which the first order sensitivity index
137            confidence interval is requested.
138        input_ : str
139            Name of the input for which the first order sensitivy index
140            confidence interval is requested.
141
142        Returns
143        -------
144        list
145            A list of two floats - lower and upper confidence interval bounds.
146        """
147        raise NotImplementedError
148
149    def _get_sobols_total_conf(self, qoi, input_):
150        """Returns confidence intervals for total order Sobol indices.
151
152        Attributes
153        ----------
154        qoi : str
155            Name of the qoi for which the first order sensitivity index
156            confidence interval is requested.
157        input_ : str
158            Name of the input for which the first order sensitivy index
159            confidence interval is requested.
160
161        Returns
162        -------
163        list
164            A list of two floats - lower and upper confidence interval bounds.
165        """
166        raise NotImplementedError
167
168    def _get_sobols_general(self, getter, qoi=None, input_=None):
169        """A generic method for getting sobol indices.
170
171        Parameters
172        ----------
173        getter: function
174             Method that takes a AnalysisResults instance and returns
175             a Sobol index of some kind. For example _get_bonols_first.
176
177        qoi: str or tuple
178            The name of the quantity of interest or None.
179            Use a tuple of the form (qoi, index) where index is integer
180            that means the coordinate index of a vector qoi.
181
182        input_: str
183            The name of the input parameter or None.
184
185        Returns
186        -------
187        dict or array
188        """
189        assert (not ((qoi is None) and (input_ is not None)))
190        if (qoi is not None) and (qoi not in self.qois):
191            raise RuntimeError('no such qoi in this analysis')
192        if (input_ is not None) and (input_ not in self.inputs):
193            raise RuntimeError('no such input variable in this analysis')
194        try:
195            if input_ is None:
196                if qoi is None:
197                    return dict([(qoi_, dict([(in_, getter(qoi_, in_))
198                                              for in_ in self.inputs]))
199                                 for qoi_ in self.qois])
200                else:
201                    return dict([(in_, getter(qoi, in_))
202                                 for in_ in self.inputs])
203            else:
204                return getter(qoi, input_)
205        except NotImplementedError:
206            raise RuntimeError(
207                'this kind of sobol index reporting not implemented in this analysis method')
208
209    def derivatives_first(self, qoi=None, input_=None):
210        """Return first order derivative-based sensitivity indices.
211
212        Parameters
213        ----------
214        qoi: str or tuple
215            The name of the quantity of interest or None.
216            Use a tuple of the form (qoi, index) where index is integer
217            that means the coordinate index of a vector qoi.
218
219        input_: str
220            The name of the input parameter or None.
221
222        Examples
223        --------
224        >>> results.derivatives_first()
225        {'f': {'x1': array([0.610242]), 'x2': array([0.26096511])}}
226        >>> results.derivatives_first('f')
227        {'x1': array([0.610242]), 'x2': array([0.26096511])}
228        >>> results.derivatives_first('f', 'x1')
229        array([0.610242])
230        >>> results_vectors.derivatives_first(('g', 2))
231        {'x1': array([0.5]), 'x2': array([0.5])}
232
233        Returns
234        -------
235        dict or array
236           If both qoi and input_ are specified will return a dictionary,
237           otherwise will return an array.
238        """
239        return self._get_sobols_general(self._get_derivatives_first, qoi, input_)
240
241    def sobols_first(self, qoi=None, input_=None):
242        """Return first order sensitivity indices.
243
244        Parameters
245        ----------
246        qoi: str or tuple
247            The name of the quantity of interest or None.
248            Use a tuple of the form (qoi, index) where index is integer
249            that means the coordinate index of a vector qoi.
250
251        input_: str
252            The name of the input parameter or None.
253
254        Examples
255        --------
256        >>> results.sobols_first()
257        {'f': {'x1': array([0.610242]), 'x2': array([0.26096511])}}
258        >>> results.sobols_first('f')
259        {'x1': array([0.610242]), 'x2': array([0.26096511])}
260        >>> results.sobols_first('f', 'x1')
261        array([0.610242])
262        >>> results_vectors.sobols_first(('g', 2))
263        {'x1': array([0.5]), 'x2': array([0.5])}
264
265        Returns
266        -------
267        dict or array
268           If both qoi and input_ are specified will return a dictionary,
269           otherwise will return an array.
270        """
271        return self._get_sobols_general(self._get_sobols_first, qoi, input_)
272
273    def sobols_second(self, qoi=None, input_=None):
274        """Return second order sensitivity indices.
275
276        Parameters
277        ----------
278        qoi: str or tuple
279            The name of the quantity of interest or None.
280            Use a tuple of the form (qoi, index) where index is integer
281            that means the coordinate index of a vector qoi.
282
283        input_: str
284            The name of the input parameter or None.
285
286        Examples
287        --------
288        >>> results.sobols_second('a')
289        {'F': {'L': array([0.000121]),
290        'a': array([0.00695338]),
291        'D': array([0.00141272])},
292        'L': {'F': array([0.000121]),
293        'a': array([0.00012737]),
294        'D': array([0.00012716])},
295        'a': {'F': array([0.00695338]),
296        'L': array([0.00012737]),
297        'D': array([0.00730415])},
298        'D': {'F': array([0.00141272]),
299        'L': array([0.00012716]),
300        'a': array([0.00730415])}}
301        >>> results.sobols_second('g1', 'L')
302        {'F': array([0.000121]), 'a': array([0.00012737]), 'D': array([0.00012716])}
303        Returns
304        -------
305        dict
306           Will always return a dictionary unlike first order sobol indices. Because
307           the index is specified by a pair of inputs. The dictionary will include
308           all inputs but `input_`.
309        """
310        return self._get_sobols_general(self._get_sobols_second, qoi, input_)
311
312    def sobols_total(self, qoi=None, input_=None):
313        """Returns total order sensitivity indices.
314
315        Parameters
316        ----------
317        qoi: str or tuple
318            The name of the quantity of interest or None.
319            Use a tuple of the form (qoi, index) where index is integer
320            that means the coordinate index of a vector qoi.
321        input_: str
322            The name of the input parameter or None.
323
324
325        Examples
326        --------
327        >>> results.sobols_total('g1')
328        {'F': array([0.14299044]),
329        'L': array([0.01247877]),
330        'a': array([0.7105291]),
331        'D': array([0.15018883])}
332        >>> results.sobols_total('g1', 'F')
333        array([0.14299044])
334
335        Returns
336        -------
337        dict or array
338           If both qoi and input_ are specified will return a dictionary,
339           otherwise will return an array.
340        """
341        return self._get_sobols_general(self._get_sobols_total, qoi, input_)
342
343    def surrogate(self):
344        """Returns the surrogate model as a function from parameter dictionary
345        to output dictionary. This only needs to be implemented if the analysis
346        method in question provides surrogate models.
347
348
349        Returns
350        -------
351        function
352            Returns a function that takes a dictionary and returns a dictionary.
353            These dictionaries use the same format as Encoder and Decoder used
354            to construct the surrogate.
355        """
356        raise NotImplementedError
357
358    def describe(self, qoi=None, statistic=None):
359        """Returns descriptive statistics.
360
361        Examples
362        --------
363        >>> results.describe()
364                     g                             h
365                     0         1         2         0         1
366        mean  0.500000  0.500000  1.000000  0.250000  0.693787
367        var   0.083333  0.083333  0.166667  0.048611  0.068236
368        std   0.288675  0.288675  0.408248  0.220479  0.261220
369        10%   0.100897  0.099462  0.441589  0.019049  0.276504
370        90%   0.896960  0.899417  1.544624  0.584600  0.974707
371        min   0.000041  0.000005  0.016687  0.000016 -0.008642
372        max   0.999998  0.999873  1.993517  0.985350  1.024599
373
374        >>> result.describe('h')
375                     h
376                     0         1
377        mean  0.250000  0.693787
378        var   0.048611  0.068236
379        std   0.220479  0.261220
380        10%   0.019049  0.276504
381        90%   0.584600  0.974707
382        min   0.000016 -0.008642
383        max   0.985350  1.024599
384
385        >>> results.describe('h', 'var')
386        array([0.04861111, 0.06823568])
387
388        Parameters
389        ----------
390        qoi: str or None
391            if not None it is the name of the quantity of interest
392        statistic: str or None
393            if not None it is the name of the statistic, currently supported ones
394            are: ['mean', 'var', 'std', '10%', '90%', 'min', 'max', 'median']
395
396        Returns
397        -------
398        DataFrame or array
399            If both quantity of interest and the statistic are specified will return
400            an array with the values for that statistic. Otherwise will return a DataFrame
401            with more data.
402        """
403        assert (not ((qoi is None) and (statistic is not None)))
404        statistics = ['mean', 'var', 'std', '1%', '10%', '90%', '99%', 'min', 'max', 'median']
405        qois = self.qois
406        if qoi is not None:
407            qois = [qoi]
408        if statistic is not None:
409            statistics = [statistic]
410        result = {}
411        for qoi in qois:
412            for statistic_ in statistics:
413                try:
414                    value = self._describe(qoi, statistic_)
415                    assert (isinstance(value, np.ndarray))
416                    for i, x in enumerate(value):
417                        try:
418                            result[(qoi, i)][statistic_] = x
419                        except KeyError:
420                            result[(qoi, i)] = {statistic_: x}
421                except NotImplementedError:
422                    if statistic is not None:
423                        raise RuntimeError(
424                            "this statistic ({}) is not reported by this analysis class".format(statistic))
425        if qois is not None and statistic is not None:
426            return pd.DataFrame(result)[qoi].loc[statistic].values
427        else:
428            return pd.DataFrame(result)
429
430    def plot_sobols_treemap(self, qoi, figsize=(10, 10), ax=None, filename=None, dpi=None):
431        """Plot sobols first and second order indices in a hierarchical treemap format.
432
433        Parameters
434        ----------
435        qoi: str
436           Name of the quantity of interest.
437        figsize: tuple
438           A tuple with two integers representing figure size in inches.
439        ax: matplotlib
440           Matplotlib axis to plot on.
441        filename: str
442           Filename to write the plot to. If left None will display to screen.
443        dpi: int
444           Dots per inches. Only used when writing to file.
445        """
446        if qoi not in self.qois:
447            raise RuntimeError("no such qoi - {}".format(qoi))
448        import matplotlib.pyplot as plt
449        import matplotlib._color_data as mcd
450        import squarify
451        sobols_first = self.sobols_first(qoi)
452        keys = list(sobols_first.keys())
453        values = [value[0] for value in list(sobols_first.values())]
454        keys = ["{}\n{:.5f}".format(key, value) for key, value in zip(keys, values)]
455        if sum(values) < 1.0:
456            keys.append("higher orders\n{:.5f}".format(1.0 - sum(values)))
457            values.append(1.0 - sum(values))
458        colors = mcd.XKCD_COLORS
459        if ax is None:
460            fig, ax = plt.subplots()
461        else:
462            fig = ax.get_figure()
463        fig.set_size_inches(figsize)
464        ax.set_title("Decomposition of {} variance".format(qoi))
465        squarify.plot(sizes=values, label=keys, color=colors, ax=ax, pad=True)
466        ax.axis('off')
467        if filename is None:
468            fig.show()
469        else:
470            fig.savefig(filename, dpi=dpi)
471
472    def plot_sobols_first(self, qoi, inputs=None, withdots=False,
473                          ylabel=None, xlabel=None, xvalues=None,
474                          filename=None, dpi=None, ax=None):
475        """Plot first order sobol indices.
476
477        Parameters
478        ----------
479        qoi: str
480            a vector quantity of interest for which sobol indices will be plotted
481        inputs: list of str or None
482            list of inputs to plot if None will use all input variables
483        withdots: bool
484            if True will add shapes on top of the lines in the plot for visual clarity
485        ylabel: str or None
486            if None will use "First Order Sobol Index"
487        xlabel: str or None
488            if None will use the name of the qoi
489        xvalues: array or None
490           x-axis coordiante if None will use range(len(qoi_values))
491        filename: str or None
492            if None will try to open a plotting window on-screen, otherwise will write the plot to this file, with the type determined by the extension specified
493        dpi: int
494            dots per inch, quality of the image if a raster format was chosen
495        ax: matplotlib axes object, default None
496            if None, plots to a new axes, otherwise plot to existing axes ax
497
498        Returns
499        -------
500        matplotlib axes object
501            the actual axes plotted to
502        """
503        if qoi not in self.qois:
504            raise RuntimeError("no such qoi - {}".format(qoi))
505        if inputs is None:
506            inputs = self.inputs
507        for input_ in inputs:
508            if input_ not in self.inputs:
509                raise RuntimeError("no such input variable - {}".format(input_))
510        import matplotlib.pyplot as plt
511        if withdots:
512            styles = itertools.cycle(['-o', '-v', '-^', '-<', '->', '-8', '-s',
513                                      '-p', '-*', '-h', '-H', '-D', '-d', '-P', '-X'])
514        else:
515            styles = itertools.cycle(['-'])
516        points = None
517        for input_ in inputs:
518            if points is None:
519                indices = self.sobols_first(qoi, input_)
520                if len(indices) < 2:
521                    raise RuntimeError('this method is only implemented for vector qois')
522                points = [indices]
523            else:
524                points.append(self.sobols_first(qoi, input_))
525        if xvalues is None:
526            xvalues = np.arange(len(points[0]))
527        if ax is None:
528            fig, ax = plt.subplots()
529        else:
530            fig = ax.get_figure()
531        higher = np.array([1.0] * len(points[0]))
532        for p, label in zip(points, inputs):
533            higher -= p
534            ax.plot(xvalues, p, next(styles), label=label)
535        ax.plot(xvalues, higher, next(styles), label='higher orders')
536        ax.grid(True)
537        if ylabel is None:
538            ax.set_ylabel('First Order Sobol Index')
539        else:
540            ax.set_ylabel(ylabel)
541        if xlabel is None:
542            ax.set_xlabel('x-axis')
543        else:
544            ax.set_xlabel(xlabel)
545        ax.legend()
546        if filename is not None:
547            fig.savefig(filename, dpi=dpi)
548        return ax
549
550    def plot_moments(
551            self,
552            qoi,
553            ylabel=None,
554            xlabel=None,
555            xvalues=None,
556            alpha=0.2,
557            filename=None,
558            dpi=None,
559            ax=None):
560        """Plot statistical moments for this analysis.
561
562        Parameters
563        ----------
564        qoi: str
565            a vector quantity of interest for which sobol indices will be plotted
566        ylabel: str or None
567            if None will use "Values"
568        xlabel: str or None
569            if None will use the name of the qoi
570        xvalues: array or None
571            x-axis coordiante if None will use range(len(qoi_values)))
572        alpha: float
573            transparency amount
574        filename: str or None
575            if None will try to open a plotting window on-screen, otherwise will
576            write the plot to this file, with the type determined by the extension specified
577        dpi: int
578            dots per inch, quality of the image if a raster format was chosen
579        ax: matplotlib axes object, default None
580            if None, plots to a new axes, otherwise plot to existing axes ax
581
582        Returns
583        -------
584        matplotlib axes object
585            the actual axes plotted to
586        """
587        if qoi not in self.qois:
588            raise RuntimeError("no such qoi - {}".format(qoi))
589        import matplotlib.pyplot as plt
590        if ax is None:
591            fig, ax = plt.subplots()
592        else:
593            fig = ax.get_figure()
594        if xvalues is None:
595            xvalues = np.arange(len(self.describe(qoi, 'mean')))
596        ax.fill_between(xvalues, self.describe(qoi, 'mean') -
597                        self.describe(qoi, 'std'), self.describe(qoi, 'mean') +
598                        self.describe(qoi, 'std'), label='std', alpha=alpha)
599        ax.plot(xvalues, self.describe(qoi, 'mean'), label='mean')
600        if all(v in self.supported_stats() for v in ['1%', '99%']):
601            ax.plot(xvalues, self.describe(qoi, '1%'), '--', label='1%', color='black')
602            ax.plot(xvalues, self.describe(qoi, '99%'), '--', label='99%', color='black')
603        ax.grid(True)
604        if ylabel is None:
605            ax.set_ylabel(qoi)
606        else:
607            ax.set_ylabel(ylabel)
608        if xlabel is None:
609            ax.set_xlabel('x-axis')
610        else:
611            ax.set_xlabel(xlabel)
612        ax.legend()
613        if filename is not None:
614            fig.savefig(filename, dpi=dpi)
615        return ax
616
617    def get_distribution(self, qoi):
618        """Returns a distribution for the given qoi.
619
620        Parameters
621        ----------
622        qoi: str
623            QoI name
624
625        Returns
626        -------
627        A ChaosPy distribution
628        """
629        raise NotImplementedError
630
631    @staticmethod
632    def _keys_to_tuples(dictionary):
633        """Convert the keys in the dictionary to tuples.
634
635        Parameters
636        ----------
637        dictionary : dict
638            A dictionary with either strings or tuples as keys.
639
640        Examples
641        --------
642        >>> AnalysisResults._keys_to_tuples({'a': 1, 'b': 2})
643        {('a', 0): 1, ('b', 0): 2})
644
645        >>> AnalysisResults._keys_to_tuples({('a', 0): 1, ('b', 0): 2})
646        {('a', 0): 1, ('b', 0): 2})
647
648        >>> AnalysisResults._keys_to_tuples({('a', 0): 1, 'b': 2})
649        {('a', 0): 1, ('b', 0): 2})
650
651        Returns
652        -------
653        A dictionary with tuples as keys.
654        """
655        new_dict = {}
656        for key in dictionary.keys():
657            new_dict[AnalysisResults._to_tuple(key)] = dictionary[key]
658        return new_dict
659
660    @staticmethod
661    def _to_tuple(key):
662        """Convert key to tuple if it is string, otherwise leave as is.
663
664        Parameters
665        ----------
666        key: str or tuple
667
668        Examples
669        --------
670        >>> AnalysisResults._to_tuple('a')
671        ('a', 0)
672
673        >>> AnalysisResults._to_tuple(('a', 0))
674        ('a', 0)
675
676        Returns
677        -------
678        Tuple if key is string, key if key is tuple.
679        """
680        if isinstance(key, tuple):
681            return key
682        elif isinstance(key, str):
683            return (key, 0)
684        else:
685            raise RuntimeError("this method expects either a string or tuple")

Contains the analysis results.

Parameters
  • raw_data (obj): An arbitrary object that contains raw analysis data.
  • samples (pandas DataFrame): Collated samples.
  • qois (list of str): List of qoi names used during the analysis.
  • inputs (list of str): List of input names used during the analysis.
AnalysisResults(raw_data=None, samples=None, qois=None, inputs=None)
34    def __init__(self, raw_data=None, samples=None, qois=None, inputs=None):
35        self.raw_data = raw_data
36        self.samples = samples
37        self.qois = qois
38        self.inputs = inputs
raw_data
samples
qois
inputs
def supported_stats(self):
40    def supported_stats(self):
41        """Returns a list of descriptive statistics that the method reports.
42
43        Examples
44        --------
45        >>> results.supported_stats()
46        ['min', 'max', '10%', '90%', '1%', '99%', 'median', 'mean', 'var', 'std']
47
48        Returns
49        -------
50        list of str
51            A list of statistics that can then be passed to the `describe` method.
52        """
53        raise NotImplementedError('descriptive statistics not available in this method')

Returns a list of descriptive statistics that the method reports.

Examples
>>> results.supported_stats()
['min', 'max', '10%', '90%', '1%', '99%', 'median', 'mean', 'var', 'std']
Returns
  • list of str: A list of statistics that can then be passed to the describe method.
def derivatives_first(self, qoi=None, input_=None):
209    def derivatives_first(self, qoi=None, input_=None):
210        """Return first order derivative-based sensitivity indices.
211
212        Parameters
213        ----------
214        qoi: str or tuple
215            The name of the quantity of interest or None.
216            Use a tuple of the form (qoi, index) where index is integer
217            that means the coordinate index of a vector qoi.
218
219        input_: str
220            The name of the input parameter or None.
221
222        Examples
223        --------
224        >>> results.derivatives_first()
225        {'f': {'x1': array([0.610242]), 'x2': array([0.26096511])}}
226        >>> results.derivatives_first('f')
227        {'x1': array([0.610242]), 'x2': array([0.26096511])}
228        >>> results.derivatives_first('f', 'x1')
229        array([0.610242])
230        >>> results_vectors.derivatives_first(('g', 2))
231        {'x1': array([0.5]), 'x2': array([0.5])}
232
233        Returns
234        -------
235        dict or array
236           If both qoi and input_ are specified will return a dictionary,
237           otherwise will return an array.
238        """
239        return self._get_sobols_general(self._get_derivatives_first, qoi, input_)

Return first order derivative-based sensitivity indices.

Parameters
  • qoi (str or tuple): The name of the quantity of interest or None. Use a tuple of the form (qoi, index) where index is integer that means the coordinate index of a vector qoi.
  • input_ (str): The name of the input parameter or None.
Examples
>>> results.derivatives_first()
{'f': {'x1': array([0.610242]), 'x2': array([0.26096511])}}
>>> results.derivatives_first('f')
{'x1': array([0.610242]), 'x2': array([0.26096511])}
>>> results.derivatives_first('f', 'x1')
array([0.610242])
>>> results_vectors.derivatives_first(('g', 2))
{'x1': array([0.5]), 'x2': array([0.5])}
Returns
  • dict or array: If both qoi and input_ are specified will return a dictionary, otherwise will return an array.
def sobols_first(self, qoi=None, input_=None):
241    def sobols_first(self, qoi=None, input_=None):
242        """Return first order sensitivity indices.
243
244        Parameters
245        ----------
246        qoi: str or tuple
247            The name of the quantity of interest or None.
248            Use a tuple of the form (qoi, index) where index is integer
249            that means the coordinate index of a vector qoi.
250
251        input_: str
252            The name of the input parameter or None.
253
254        Examples
255        --------
256        >>> results.sobols_first()
257        {'f': {'x1': array([0.610242]), 'x2': array([0.26096511])}}
258        >>> results.sobols_first('f')
259        {'x1': array([0.610242]), 'x2': array([0.26096511])}
260        >>> results.sobols_first('f', 'x1')
261        array([0.610242])
262        >>> results_vectors.sobols_first(('g', 2))
263        {'x1': array([0.5]), 'x2': array([0.5])}
264
265        Returns
266        -------
267        dict or array
268           If both qoi and input_ are specified will return a dictionary,
269           otherwise will return an array.
270        """
271        return self._get_sobols_general(self._get_sobols_first, qoi, input_)

Return first order sensitivity indices.

Parameters
  • qoi (str or tuple): The name of the quantity of interest or None. Use a tuple of the form (qoi, index) where index is integer that means the coordinate index of a vector qoi.
  • input_ (str): The name of the input parameter or None.
Examples
>>> results.sobols_first()
{'f': {'x1': array([0.610242]), 'x2': array([0.26096511])}}
>>> results.sobols_first('f')
{'x1': array([0.610242]), 'x2': array([0.26096511])}
>>> results.sobols_first('f', 'x1')
array([0.610242])
>>> results_vectors.sobols_first(('g', 2))
{'x1': array([0.5]), 'x2': array([0.5])}
Returns
  • dict or array: If both qoi and input_ are specified will return a dictionary, otherwise will return an array.
def sobols_second(self, qoi=None, input_=None):
273    def sobols_second(self, qoi=None, input_=None):
274        """Return second order sensitivity indices.
275
276        Parameters
277        ----------
278        qoi: str or tuple
279            The name of the quantity of interest or None.
280            Use a tuple of the form (qoi, index) where index is integer
281            that means the coordinate index of a vector qoi.
282
283        input_: str
284            The name of the input parameter or None.
285
286        Examples
287        --------
288        >>> results.sobols_second('a')
289        {'F': {'L': array([0.000121]),
290        'a': array([0.00695338]),
291        'D': array([0.00141272])},
292        'L': {'F': array([0.000121]),
293        'a': array([0.00012737]),
294        'D': array([0.00012716])},
295        'a': {'F': array([0.00695338]),
296        'L': array([0.00012737]),
297        'D': array([0.00730415])},
298        'D': {'F': array([0.00141272]),
299        'L': array([0.00012716]),
300        'a': array([0.00730415])}}
301        >>> results.sobols_second('g1', 'L')
302        {'F': array([0.000121]), 'a': array([0.00012737]), 'D': array([0.00012716])}
303        Returns
304        -------
305        dict
306           Will always return a dictionary unlike first order sobol indices. Because
307           the index is specified by a pair of inputs. The dictionary will include
308           all inputs but `input_`.
309        """
310        return self._get_sobols_general(self._get_sobols_second, qoi, input_)

Return second order sensitivity indices.

Parameters
  • qoi (str or tuple): The name of the quantity of interest or None. Use a tuple of the form (qoi, index) where index is integer that means the coordinate index of a vector qoi.
  • input_ (str): The name of the input parameter or None.
Examples
>>> results.sobols_second('a')
{'F': {'L': array([0.000121]),
'a': array([0.00695338]),
'D': array([0.00141272])},
'L': {'F': array([0.000121]),
'a': array([0.00012737]),
'D': array([0.00012716])},
'a': {'F': array([0.00695338]),
'L': array([0.00012737]),
'D': array([0.00730415])},
'D': {'F': array([0.00141272]),
'L': array([0.00012716]),
'a': array([0.00730415])}}
>>> results.sobols_second('g1', 'L')
{'F': array([0.000121]), 'a': array([0.00012737]), 'D': array([0.00012716])}
<h6 id="returns">Returns</h6>
  • dict: Will always return a dictionary unlike first order sobol indices. Because the index is specified by a pair of inputs. The dictionary will include all inputs but input_.
def sobols_total(self, qoi=None, input_=None):
312    def sobols_total(self, qoi=None, input_=None):
313        """Returns total order sensitivity indices.
314
315        Parameters
316        ----------
317        qoi: str or tuple
318            The name of the quantity of interest or None.
319            Use a tuple of the form (qoi, index) where index is integer
320            that means the coordinate index of a vector qoi.
321        input_: str
322            The name of the input parameter or None.
323
324
325        Examples
326        --------
327        >>> results.sobols_total('g1')
328        {'F': array([0.14299044]),
329        'L': array([0.01247877]),
330        'a': array([0.7105291]),
331        'D': array([0.15018883])}
332        >>> results.sobols_total('g1', 'F')
333        array([0.14299044])
334
335        Returns
336        -------
337        dict or array
338           If both qoi and input_ are specified will return a dictionary,
339           otherwise will return an array.
340        """
341        return self._get_sobols_general(self._get_sobols_total, qoi, input_)

Returns total order sensitivity indices.

Parameters
  • qoi (str or tuple): The name of the quantity of interest or None. Use a tuple of the form (qoi, index) where index is integer that means the coordinate index of a vector qoi.
  • input_ (str): The name of the input parameter or None.
Examples
>>> results.sobols_total('g1')
{'F': array([0.14299044]),
'L': array([0.01247877]),
'a': array([0.7105291]),
'D': array([0.15018883])}
>>> results.sobols_total('g1', 'F')
array([0.14299044])
Returns
  • dict or array: If both qoi and input_ are specified will return a dictionary, otherwise will return an array.
def surrogate(self):
343    def surrogate(self):
344        """Returns the surrogate model as a function from parameter dictionary
345        to output dictionary. This only needs to be implemented if the analysis
346        method in question provides surrogate models.
347
348
349        Returns
350        -------
351        function
352            Returns a function that takes a dictionary and returns a dictionary.
353            These dictionaries use the same format as Encoder and Decoder used
354            to construct the surrogate.
355        """
356        raise NotImplementedError

Returns the surrogate model as a function from parameter dictionary to output dictionary. This only needs to be implemented if the analysis method in question provides surrogate models.

Returns
  • function: Returns a function that takes a dictionary and returns a dictionary. These dictionaries use the same format as Encoder and Decoder used to construct the surrogate.
def describe(self, qoi=None, statistic=None):
358    def describe(self, qoi=None, statistic=None):
359        """Returns descriptive statistics.
360
361        Examples
362        --------
363        >>> results.describe()
364                     g                             h
365                     0         1         2         0         1
366        mean  0.500000  0.500000  1.000000  0.250000  0.693787
367        var   0.083333  0.083333  0.166667  0.048611  0.068236
368        std   0.288675  0.288675  0.408248  0.220479  0.261220
369        10%   0.100897  0.099462  0.441589  0.019049  0.276504
370        90%   0.896960  0.899417  1.544624  0.584600  0.974707
371        min   0.000041  0.000005  0.016687  0.000016 -0.008642
372        max   0.999998  0.999873  1.993517  0.985350  1.024599
373
374        >>> result.describe('h')
375                     h
376                     0         1
377        mean  0.250000  0.693787
378        var   0.048611  0.068236
379        std   0.220479  0.261220
380        10%   0.019049  0.276504
381        90%   0.584600  0.974707
382        min   0.000016 -0.008642
383        max   0.985350  1.024599
384
385        >>> results.describe('h', 'var')
386        array([0.04861111, 0.06823568])
387
388        Parameters
389        ----------
390        qoi: str or None
391            if not None it is the name of the quantity of interest
392        statistic: str or None
393            if not None it is the name of the statistic, currently supported ones
394            are: ['mean', 'var', 'std', '10%', '90%', 'min', 'max', 'median']
395
396        Returns
397        -------
398        DataFrame or array
399            If both quantity of interest and the statistic are specified will return
400            an array with the values for that statistic. Otherwise will return a DataFrame
401            with more data.
402        """
403        assert (not ((qoi is None) and (statistic is not None)))
404        statistics = ['mean', 'var', 'std', '1%', '10%', '90%', '99%', 'min', 'max', 'median']
405        qois = self.qois
406        if qoi is not None:
407            qois = [qoi]
408        if statistic is not None:
409            statistics = [statistic]
410        result = {}
411        for qoi in qois:
412            for statistic_ in statistics:
413                try:
414                    value = self._describe(qoi, statistic_)
415                    assert (isinstance(value, np.ndarray))
416                    for i, x in enumerate(value):
417                        try:
418                            result[(qoi, i)][statistic_] = x
419                        except KeyError:
420                            result[(qoi, i)] = {statistic_: x}
421                except NotImplementedError:
422                    if statistic is not None:
423                        raise RuntimeError(
424                            "this statistic ({}) is not reported by this analysis class".format(statistic))
425        if qois is not None and statistic is not None:
426            return pd.DataFrame(result)[qoi].loc[statistic].values
427        else:
428            return pd.DataFrame(result)

Returns descriptive statistics.

Examples
>>> results.describe()
             g                             h
             0         1         2         0         1
mean  0.500000  0.500000  1.000000  0.250000  0.693787
var   0.083333  0.083333  0.166667  0.048611  0.068236
std   0.288675  0.288675  0.408248  0.220479  0.261220
10%   0.100897  0.099462  0.441589  0.019049  0.276504
90%   0.896960  0.899417  1.544624  0.584600  0.974707
min   0.000041  0.000005  0.016687  0.000016 -0.008642
max   0.999998  0.999873  1.993517  0.985350  1.024599
>>> result.describe('h')
             h
             0         1
mean  0.250000  0.693787
var   0.048611  0.068236
std   0.220479  0.261220
10%   0.019049  0.276504
90%   0.584600  0.974707
min   0.000016 -0.008642
max   0.985350  1.024599
>>> results.describe('h', 'var')
array([0.04861111, 0.06823568])
Parameters
  • qoi (str or None): if not None it is the name of the quantity of interest
  • statistic (str or None): if not None it is the name of the statistic, currently supported ones are: ['mean', 'var', 'std', '10%', '90%', 'min', 'max', 'median']
Returns
  • DataFrame or array: If both quantity of interest and the statistic are specified will return an array with the values for that statistic. Otherwise will return a DataFrame with more data.
def plot_sobols_treemap(self, qoi, figsize=(10, 10), ax=None, filename=None, dpi=None):
430    def plot_sobols_treemap(self, qoi, figsize=(10, 10), ax=None, filename=None, dpi=None):
431        """Plot sobols first and second order indices in a hierarchical treemap format.
432
433        Parameters
434        ----------
435        qoi: str
436           Name of the quantity of interest.
437        figsize: tuple
438           A tuple with two integers representing figure size in inches.
439        ax: matplotlib
440           Matplotlib axis to plot on.
441        filename: str
442           Filename to write the plot to. If left None will display to screen.
443        dpi: int
444           Dots per inches. Only used when writing to file.
445        """
446        if qoi not in self.qois:
447            raise RuntimeError("no such qoi - {}".format(qoi))
448        import matplotlib.pyplot as plt
449        import matplotlib._color_data as mcd
450        import squarify
451        sobols_first = self.sobols_first(qoi)
452        keys = list(sobols_first.keys())
453        values = [value[0] for value in list(sobols_first.values())]
454        keys = ["{}\n{:.5f}".format(key, value) for key, value in zip(keys, values)]
455        if sum(values) < 1.0:
456            keys.append("higher orders\n{:.5f}".format(1.0 - sum(values)))
457            values.append(1.0 - sum(values))
458        colors = mcd.XKCD_COLORS
459        if ax is None:
460            fig, ax = plt.subplots()
461        else:
462            fig = ax.get_figure()
463        fig.set_size_inches(figsize)
464        ax.set_title("Decomposition of {} variance".format(qoi))
465        squarify.plot(sizes=values, label=keys, color=colors, ax=ax, pad=True)
466        ax.axis('off')
467        if filename is None:
468            fig.show()
469        else:
470            fig.savefig(filename, dpi=dpi)

Plot sobols first and second order indices in a hierarchical treemap format.

Parameters
  • qoi (str): Name of the quantity of interest.
  • figsize (tuple): A tuple with two integers representing figure size in inches.
  • ax (matplotlib): Matplotlib axis to plot on.
  • filename (str): Filename to write the plot to. If left None will display to screen.
  • dpi (int): Dots per inches. Only used when writing to file.
def plot_sobols_first( self, qoi, inputs=None, withdots=False, ylabel=None, xlabel=None, xvalues=None, filename=None, dpi=None, ax=None):
472    def plot_sobols_first(self, qoi, inputs=None, withdots=False,
473                          ylabel=None, xlabel=None, xvalues=None,
474                          filename=None, dpi=None, ax=None):
475        """Plot first order sobol indices.
476
477        Parameters
478        ----------
479        qoi: str
480            a vector quantity of interest for which sobol indices will be plotted
481        inputs: list of str or None
482            list of inputs to plot if None will use all input variables
483        withdots: bool
484            if True will add shapes on top of the lines in the plot for visual clarity
485        ylabel: str or None
486            if None will use "First Order Sobol Index"
487        xlabel: str or None
488            if None will use the name of the qoi
489        xvalues: array or None
490           x-axis coordiante if None will use range(len(qoi_values))
491        filename: str or None
492            if None will try to open a plotting window on-screen, otherwise will write the plot to this file, with the type determined by the extension specified
493        dpi: int
494            dots per inch, quality of the image if a raster format was chosen
495        ax: matplotlib axes object, default None
496            if None, plots to a new axes, otherwise plot to existing axes ax
497
498        Returns
499        -------
500        matplotlib axes object
501            the actual axes plotted to
502        """
503        if qoi not in self.qois:
504            raise RuntimeError("no such qoi - {}".format(qoi))
505        if inputs is None:
506            inputs = self.inputs
507        for input_ in inputs:
508            if input_ not in self.inputs:
509                raise RuntimeError("no such input variable - {}".format(input_))
510        import matplotlib.pyplot as plt
511        if withdots:
512            styles = itertools.cycle(['-o', '-v', '-^', '-<', '->', '-8', '-s',
513                                      '-p', '-*', '-h', '-H', '-D', '-d', '-P', '-X'])
514        else:
515            styles = itertools.cycle(['-'])
516        points = None
517        for input_ in inputs:
518            if points is None:
519                indices = self.sobols_first(qoi, input_)
520                if len(indices) < 2:
521                    raise RuntimeError('this method is only implemented for vector qois')
522                points = [indices]
523            else:
524                points.append(self.sobols_first(qoi, input_))
525        if xvalues is None:
526            xvalues = np.arange(len(points[0]))
527        if ax is None:
528            fig, ax = plt.subplots()
529        else:
530            fig = ax.get_figure()
531        higher = np.array([1.0] * len(points[0]))
532        for p, label in zip(points, inputs):
533            higher -= p
534            ax.plot(xvalues, p, next(styles), label=label)
535        ax.plot(xvalues, higher, next(styles), label='higher orders')
536        ax.grid(True)
537        if ylabel is None:
538            ax.set_ylabel('First Order Sobol Index')
539        else:
540            ax.set_ylabel(ylabel)
541        if xlabel is None:
542            ax.set_xlabel('x-axis')
543        else:
544            ax.set_xlabel(xlabel)
545        ax.legend()
546        if filename is not None:
547            fig.savefig(filename, dpi=dpi)
548        return ax

Plot first order sobol indices.

Parameters
  • qoi (str): a vector quantity of interest for which sobol indices will be plotted
  • inputs (list of str or None): list of inputs to plot if None will use all input variables
  • withdots (bool): if True will add shapes on top of the lines in the plot for visual clarity
  • ylabel (str or None): if None will use "First Order Sobol Index"
  • xlabel (str or None): if None will use the name of the qoi
  • xvalues (array or None): x-axis coordiante if None will use range(len(qoi_values))
  • filename (str or None): if None will try to open a plotting window on-screen, otherwise will write the plot to this file, with the type determined by the extension specified
  • dpi (int): dots per inch, quality of the image if a raster format was chosen
  • ax (matplotlib axes object, default None): if None, plots to a new axes, otherwise plot to existing axes ax
Returns
  • matplotlib axes object: the actual axes plotted to
def plot_moments( self, qoi, ylabel=None, xlabel=None, xvalues=None, alpha=0.2, filename=None, dpi=None, ax=None):
550    def plot_moments(
551            self,
552            qoi,
553            ylabel=None,
554            xlabel=None,
555            xvalues=None,
556            alpha=0.2,
557            filename=None,
558            dpi=None,
559            ax=None):
560        """Plot statistical moments for this analysis.
561
562        Parameters
563        ----------
564        qoi: str
565            a vector quantity of interest for which sobol indices will be plotted
566        ylabel: str or None
567            if None will use "Values"
568        xlabel: str or None
569            if None will use the name of the qoi
570        xvalues: array or None
571            x-axis coordiante if None will use range(len(qoi_values)))
572        alpha: float
573            transparency amount
574        filename: str or None
575            if None will try to open a plotting window on-screen, otherwise will
576            write the plot to this file, with the type determined by the extension specified
577        dpi: int
578            dots per inch, quality of the image if a raster format was chosen
579        ax: matplotlib axes object, default None
580            if None, plots to a new axes, otherwise plot to existing axes ax
581
582        Returns
583        -------
584        matplotlib axes object
585            the actual axes plotted to
586        """
587        if qoi not in self.qois:
588            raise RuntimeError("no such qoi - {}".format(qoi))
589        import matplotlib.pyplot as plt
590        if ax is None:
591            fig, ax = plt.subplots()
592        else:
593            fig = ax.get_figure()
594        if xvalues is None:
595            xvalues = np.arange(len(self.describe(qoi, 'mean')))
596        ax.fill_between(xvalues, self.describe(qoi, 'mean') -
597                        self.describe(qoi, 'std'), self.describe(qoi, 'mean') +
598                        self.describe(qoi, 'std'), label='std', alpha=alpha)
599        ax.plot(xvalues, self.describe(qoi, 'mean'), label='mean')
600        if all(v in self.supported_stats() for v in ['1%', '99%']):
601            ax.plot(xvalues, self.describe(qoi, '1%'), '--', label='1%', color='black')
602            ax.plot(xvalues, self.describe(qoi, '99%'), '--', label='99%', color='black')
603        ax.grid(True)
604        if ylabel is None:
605            ax.set_ylabel(qoi)
606        else:
607            ax.set_ylabel(ylabel)
608        if xlabel is None:
609            ax.set_xlabel('x-axis')
610        else:
611            ax.set_xlabel(xlabel)
612        ax.legend()
613        if filename is not None:
614            fig.savefig(filename, dpi=dpi)
615        return ax

Plot statistical moments for this analysis.

Parameters
  • qoi (str): a vector quantity of interest for which sobol indices will be plotted
  • ylabel (str or None): if None will use "Values"
  • xlabel (str or None): if None will use the name of the qoi
  • xvalues (array or None): x-axis coordiante if None will use range(len(qoi_values)))
  • alpha (float): transparency amount
  • filename (str or None): if None will try to open a plotting window on-screen, otherwise will write the plot to this file, with the type determined by the extension specified
  • dpi (int): dots per inch, quality of the image if a raster format was chosen
  • ax (matplotlib axes object, default None): if None, plots to a new axes, otherwise plot to existing axes ax
Returns
  • matplotlib axes object: the actual axes plotted to
def get_distribution(self, qoi):
617    def get_distribution(self, qoi):
618        """Returns a distribution for the given qoi.
619
620        Parameters
621        ----------
622        qoi: str
623            QoI name
624
625        Returns
626        -------
627        A ChaosPy distribution
628        """
629        raise NotImplementedError

Returns a distribution for the given qoi.

Parameters
  • qoi (str): QoI name
Returns
  • A ChaosPy distribution