@@ -52,7 +52,7 @@ def screeningplan(k, p, xi, r):
5252 return X
5353
5454
55- def screening (X , fun , xi , p , labels , range = None , print = False ) -> pd .DataFrame :
55+ def screening (X , fun , xi , p , labels , bounds = None , print = False ) -> pd .DataFrame :
5656 """Generates a DataFrame with elementary effect screening metrics.
5757
5858 This function calculates the mean and standard deviation of the
@@ -68,7 +68,7 @@ def screening(X, fun, xi, p, labels, range=None, print=False) -> pd.DataFrame:
6868 p (int): Number of discrete levels along each dimension.
6969 labels (list of str): A list of variable names corresponding to
7070 the design variables.
71- range (np.ndarray): A 2xk matrix where the first row contains
71+ bounds (np.ndarray): A 2xk matrix where the first row contains
7272 lower bounds and the second row contains upper bounds for
7373 each variable.
7474
@@ -78,66 +78,74 @@ def screening(X, fun, xi, p, labels, range=None, print=False) -> pd.DataFrame:
7878 - 'mean': The mean of the elementary effects for each variable.
7979 - 'sd': The standard deviation of the elementary effects for
8080 each variable.
81+ or None: If print is set to False, a plot of the results is
82+ generated instead of returning a DataFrame.
8183
8284 Examples:
8385 >>> import numpy as np
84- >>> from spotpython.fun.objectivefunctions import Analytical
85- >>> from spotpython.utils.effects import screening
86- >>>
87- >>> # Create a small test input with shape (n, 10)
88- >>> X_test = np.array([
89- ... [0.0]*10,
90- ... [1.0]*10
91- ... ])
92- >>> fun = Analytical()
93- >>> labels = ["x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10"]
94- >>> result = screening(X_test, fun.fun_wingwt, np.array([[0]*10, [1]*10]), 0.1, 3, labels)
95- >>> print
86+ from spotpython.utils.effects import screening, screeningplan
87+ from spotpython.fun.objectivefunctions import Analytical
88+ fun = Analytical()
89+ k = 10
90+ p = 10
91+ xi = 1
92+ r = 25
93+ X = screeningplan(k=k, p=p, xi=xi, r=r) # shape (r x (k+1), k)
94+ # Provide real-world bounds from the wing weight docs (2 x 10).
95+ value_range = np.array([
96+ [150, 220, 6, -10, 16, 0.5, 0.08, 2.5, 1700, 0.025],
97+ [200, 300, 10, 10, 45, 1.0, 0.18, 6.0, 2500, 0.08 ],
98+ ])
99+ labels = [
100+ "S_W", "W_fw", "A", "Lambda",
101+ "q", "lambda", "tc", "N_z",
102+ "W_dg", "W_p"
103+ ]
104+ screening(
105+ X=X,
106+ fun=fun.fun_wingwt,
107+ bounds=value_range,
108+ xi=xi,
109+ p=p,
110+ labels=labels,
111+ print=False,
112+ )
96113 """
97- # Determine the number of design variables (k)
98114 k = X .shape [1 ]
99- # Determine the number of repetitions (r)
100115 r = X .shape [0 ] // (k + 1 )
101116
102- # Scale each design point to the given range and evaluate the objective function
117+ # Scale each design point
103118 t = np .zeros (X .shape [0 ])
104119 for i in range (X .shape [0 ]):
105- if range is not None :
106- X [i , :] = range [0 , :] + X [i , :] * (range [1 , :] - range [0 , :])
120+ if bounds is not None :
121+ X [i , :] = bounds [0 , :] + X [i , :] * (bounds [1 , :] - bounds [0 , :])
107122 t [i ] = fun (X [i , :])
108123
109- # Calculate the elementary effects
124+ # Elementary effects
110125 F = np .zeros ((k , r ))
111126 for i in range (r ):
112127 for j in range (i * (k + 1 ), i * (k + 1 ) + k ):
113- index = np .where (X [j , :] - X [j + 1 , :] != 0 )[0 ][0 ]
114- F [index , i ] = (t [j + 1 ] - t [j ]) / (xi / (p - 1 ))
128+ idx = np .where (X [j , :] - X [j + 1 , :] != 0 )[0 ][0 ]
129+ F [idx , i ] = (t [j + 1 ] - t [j ]) / (xi / (p - 1 ))
115130
116- # Compute statistical measures
117- ssd = np .std (F , axis = 1 )
118- sm = np .abs ( np . mean (F , axis = 1 ) )
131+ # Statistical measures (divide by n)
132+ ssd = np .std (F , axis = 1 , ddof = 0 )
133+ sm = np .mean (F , axis = 1 )
119134
120135 if print :
121- # sort the variables by decreasing mean
122- idx = np .argsort (- sm )
123- labels = [labels [i ] for i in idx ]
136+ idx = np .argsort (- np .abs (sm ))
137+ sorted_labels = [labels [i ] for i in idx ]
124138 sm = sm [idx ]
125139 ssd = ssd [idx ]
126- df = pd .DataFrame ({"varname" : labels , "mean" : sm , "sd" : ssd })
127-
140+ df = pd .DataFrame ({"varname" : sorted_labels , "mean" : sm , "sd" : ssd })
128141 return df
129142 else :
130- # Generate plot
131143 plt .figure ()
132-
133144 for i in range (k ):
134145 plt .text (sm [i ], ssd [i ], labels [i ], fontsize = 10 )
135-
136146 plt .axis ([min (sm ), 1.1 * max (sm ), min (ssd ), 1.1 * max (ssd )])
137147 plt .xlabel ("Sample means" )
138148 plt .ylabel ("Sample standard deviations" )
139- plt .gca ().set_xlabel ("Sample means" )
140- plt .gca ().set_ylabel ("Sample standard deviations" )
141149 plt .gca ().tick_params (labelsize = 10 )
142150 plt .grid (True )
143151 plt .show ()
0 commit comments