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")
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.
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
describemethod.
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.
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.
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_.
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.
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.
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.
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.
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
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
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