File: plot_sensitivity_par_coo_ishigami.py

package info (click to toggle)
openturns 1.24-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 66,204 kB
  • sloc: cpp: 256,662; python: 63,381; ansic: 4,414; javascript: 406; sh: 180; xml: 164; yacc: 123; makefile: 98; lex: 55
file content (184 lines) | stat: -rw-r--r-- 6,517 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
"""
Visualize sensitivity
=====================
"""

# %%
# The parallel coordinates graph enables to visualize all the combinations of the input
# variables which lead to a specific range of the output variable. It is a very simple and cheap tool to visualize sensitivity from the raw data.
#
# Let us consider a model :math:`f: \mathbb{R}^n \longrightarrow \mathbb{R}`, where :math:`f(\underline{X}) = Y`.
#
# The graph requires to have an input sample :math:`X_s` and an output sample :math:`Y_s`.
#
# The first figure draws such a graph: each column represents one component
# :math:`X_i` of the input vector :math:`\underline{X}`.
# The last column represents the scalar output variable :math:`Y`.
# For each point :math:`\underline{X}^j`, each component :math:`X_i^j`
# is noted on its respective axe and the last mark is the one which corresponds to
# the associated :math:`Y^j`. A line joins all the marks. Thus, each point of the sample
# corresponds to a particular line on the graph.
#
# The scale of the axes are quantile based: each axe runs between 0 and 1 and each
# value is represented by its quantile with respect to its marginal empirical distribution.
#
# It is interesting to select, among those lines, the ones which correspond to a specific range of the output variable.
# These particular lines are colored differently.
# This specific range is defined in the quantile based scale of :math:`Y` or in its specific scale.
# In that second case, the range is automatically converted into a quantile based scale range.

# %%
from openturns.usecases.ishigami_function import IshigamiModel
import openturns as ot
import openturns.viewer as viewer
from matplotlib import pylab as plt

ot.Log.Show(ot.Log.NONE)

# %%
# We load the :ref:`Ishigami model<use-case-ishigami>` from the `usecases` module :
im = IshigamiModel()
# the Ishigami function
model = im.model
# the input distribution
inputDist = im.inputDistribution

# %%
# We create a random vector from out input distribution :
inputVector = ot.RandomVector(inputDist)

# %%
# And we create the output random vector :math:`Y = model(X)` :
output = ot.CompositeRandomVector(model, inputVector)

# %%
# We generate an input sample of size :math:`N` :
N = 1000
X = inputVector.getSample(N)

# %%
# We evaluate the associated output sample :
Y = model(X)
Y.setDescription("Y")

# %%
# We display the minimum, maximum and value of the 90% quantile of :math:`Y` :
print(Y.getMin(), Y.getMax(), Y.computeQuantilePerComponent(0.9))

# %%
# Value based scale to describe the Y range
# -----------------------------------------
#
# Say we are interested in the higher values of the output :math:`Y`. A first
# approach is to highlight peculiar lines for which :math:`Y \in [a,b]` with
# the bounds :math:`a` and :math:`b` well chosen. For example, values greater
# than 85% of the maximum :
#
#  - :math:`a = 0.85 \max(Y)` ;
#  - :math:`b = \max(Y)` ;
#
minValue = 0.85 * Y.getMax()[0]
maxValue = Y.getMax()[0]

# We deactivate the default quantile scale.
quantileScale = False
graph = ot.VisualTest.DrawParallelCoordinates(
    X, Y, minValue, maxValue, "red", quantileScale
)
graph.setLegendPosition("lower right")
view = viewer.View(graph)

# %%
# Here we would like to conclude that the highest values of :math:`Y` are obtained from a specific input as the highlighted lines clearly follow one only path.
# However, this approach is too naive and specific to the input sample. Indeed,
# if we set the lower bound to 80% of the maximum :

# %%
minValue = 0.80 * Y.getMax()[0]
maxValue = Y.getMax()[0]
quantileScale = False
graph = ot.VisualTest.DrawParallelCoordinates(
    X, Y, minValue, maxValue, "red", quantileScale
)
graph.setLegendPosition("lower right")
view = viewer.View(graph)

# %%
# A new path is then available ! That is the reason why we chose a quantile based ranking as the value based parallel plot involves a bit of guessing.


# %%
# Rank based scale to describe the Y range
# ---------------------------------------------------
#
# In this paragraph we use quantile based bounds. We are still interested in
# the highest values of :math:`Y` more specifically the 95% quantile :

# %%
minValue = 0.95
maxValue = 1.0
# a quantileScale is used, default behaviour
quantileScale = True
graph = ot.VisualTest.DrawParallelCoordinates(
    X, Y, minValue, maxValue, "red", quantileScale
)
graph.setLegendPosition("lower right")
view = viewer.View(graph)

# %%
# The parallel coordinates plot obtained is helpful : we see peculiar values for each marginal.
#

# %%
# Recall that the Ishigami model is given by
#
# .. math::
#    f(X) = \sin(X_1) + 7 \sin^2(X_2) + 0.1 X_3^4 \sin(X_1)
#
# with each marginal of :math:`X=(X_1, X_2, X_3)` uniform in :math:`]-\pi,\pi[`.
#
# Then the highest values of :math:`Y=f(X)` are obtained when each term is near its peak :
#
# - the :math:`\sin(X_1)` term around :math:`X_1 = \frac{\pi}{2}` ;
# - the :math:`7 \sin^2(X_2)` term around :math:`X_2 = -\frac{\pi}{2}` and :math:`X_2 = \frac{\pi}{2}` ;
# - the :math:`X_3^4 \sin(X_1)` term around :math:`X_1 = \frac{\pi}{2}` and :math:`X_3 = \{ -\pi, \pi \}`.
#
# These values can be seen on the parallel plot as for each marginal there is a
# cluster around respectively 1, 2 and 2 values for :math:`X_1`, :math:`X_2` and :math:`X_3`.
# This amounts to 4 different values 'realizing' the maximum and we can observe
# 4 distinct paths on the parallel plot as well.
#

# %%
# We can also guess the independence of marginals when looking at paths between
# :math:`X_2` and :math:`X_3`. For any given cluster value of :math:`X_2` on the
# graph there are as many paths to a high value of :math:`X_3` as to a small value.
# A dependence between these two marginals would have presented unbalanced paths.

# %%
# When the parallel plot brings nothing
# -------------------------------------
#
# To conclude our tour on the parallel plot we look at the 50% quantile : that is
# values around the mean :

# %%
minValue = 0.48
maxValue = 0.52
quantileScale = True
graph = ot.VisualTest.DrawParallelCoordinates(
    X, Y, minValue, maxValue, "red", quantileScale
)
graph.setLegendPosition("upper right")
view = viewer.View(graph)

# %%
# We cannot extract any useful information from this parallel plot.
# In fact it is the expected behaviour as mean values should be attained from
# various combinations of# the input variables.
# The parallel coordinates graph is a cheap tool and highly useful to explore
# more extreme values!

# %%
# Display figures
plt.show()