|
7 | 7 | """ |
8 | 8 |
|
9 | 9 | # %% |
10 | | -# First import some libraries |
| 10 | +# First, import some libraries |
11 | 11 | from matplotlib import pyplot as plt |
12 | 12 |
|
13 | 13 | import numpy as np |
|
51 | 51 | # The test compares distributions of different missing patterns. |
52 | 52 | # |
53 | 53 | # The null hypothesis, H0, is: "Distributions within each pattern are similar.". |
54 | | -# We choose to use the classic threshold of 5%. If the test p-value is below this threshold, |
| 54 | +# We choose to use the classical threshold of 5%. If the test p-value is below this threshold, |
55 | 55 | # we reject the null hypothesis. |
56 | 56 | # This notebook shows how the Little and PKLM tests perform on a simplistic case and their |
57 | 57 | # limitations. We instantiate a test object with a random state for reproducibility. |
|
102 | 102 | print(f"The p-value of the PKLM test is: {pklm_result:.2%}") |
103 | 103 | # %% |
104 | 104 | # The two p-values are larger than 0.05, therefore we don't reject the H0 MCAR assumption. |
105 | | -# In this case this is a true negative. |
| 105 | +# In this case, this is a true negative. |
106 | 106 |
|
107 | 107 | # %% |
108 | 108 | # Case 2: MAR holes with mean bias (True positive) |
|
147 | 147 | print(f"The p-value of the PKLM test is: {pklm_result:.2%}") |
148 | 148 | # %% |
149 | 149 | # The two p-values are smaller than 0.05, therefore we reject the H0 MCAR assumption. |
150 | | -# In this case this is a true positive. |
| 150 | +# In this case, this is a true positive. |
151 | 151 |
|
152 | 152 | # %% |
153 | 153 | # Case 3: MAR holes with any mean bias (False negative) |
154 | 154 | # ===================================================== |
155 | 155 | # |
156 | | -# The specific case is designed to emphasize the Little's test limits. In the case, we generate |
| 156 | +# The specific case is designed to emphasize the Little's test limits. In this case, we generate |
157 | 157 | # holes when the absolute value of the first feature is high. This missingness mechanism is clearly |
158 | 158 | # MAR but the means between missing patterns is not statistically different. |
159 | 159 |
|
|
197 | 197 | print(f"The p-value of the PKLM test is: {pklm_result:.2%}") |
198 | 198 | # %% |
199 | 199 | # The Little's p-value is larger than 0.05, therefore, using this test we don't reject the H0 MCAR |
200 | | -# assumption. In this case this is a false negative since the missingness mechanism is MAR. |
| 200 | +# assumption. In this case, this is a false negative since the missingness mechanism is MAR. |
201 | 201 | # |
202 | | -# However the PKLM test p-value is smaller than 0.05 therefore we don't reject the H0 MCAR |
203 | | -# assumption. In this case this is a true negative. |
| 202 | +# However the PKLM test p-value is smaller than 0.05 therefore we reject the H0 MCAR |
| 203 | +# assumption. In this case, this is a true negative. |
204 | 204 |
|
205 | 205 | # %% |
206 | 206 | # Limitations and conclusion |
207 | 207 | # ========================== |
208 | 208 | # In this tutorial, we can see that Little's test fails to detect covariance heterogeneity between |
209 | 209 | # patterns. |
210 | 210 | # |
211 | | -# We also note that the Little's test does not handle categorical data or temporally |
| 211 | +# We also note that Little's test does not handle categorical data or temporally |
212 | 212 | # correlated data. |
213 | 213 | # |
214 | 214 | # This is why we have implemented the PKLM test, which makes up for the shortcomings of the Little |
|
231 | 231 | # |
232 | 232 |
|
233 | 233 | # %% |
234 | | - |
235 | | -""" |
236 | | -Calculation time |
237 | | -================ |
238 | | -
|
239 | | -+------------+------------+----------------------+ |
240 | | -| **n_rows** | **n_cols** | **Calculation_time** | |
241 | | -+============+============+======================+ |
242 | | -| 200 | 2 | 2"12 | |
243 | | -+------------+------------+----------------------+ |
244 | | -| 500 | 2 | 2"24 | |
245 | | -+------------+------------+----------------------+ |
246 | | -| 500 | 4 | 2"18 | |
247 | | -+------------+------------+----------------------+ |
248 | | -| 1000 | 4 | 2"48 | |
249 | | -+------------+------------+----------------------+ |
250 | | -| 1000 | 6 | 2"42 | |
251 | | -+------------+------------+----------------------+ |
252 | | -| 10000 | 6 | 20"54 | |
253 | | -+------------+------------+----------------------+ |
254 | | -| 10000 | 10 | 14"48 | |
255 | | -+------------+------------+----------------------+ |
256 | | -| 100000 | 10 | 4'51" | |
257 | | -+------------+------------+----------------------+ |
258 | | -| 100000 | 15 | 3'06" | |
259 | | -+------------+------------+----------------------+ |
260 | | -""" |
| 234 | +# Calculation time |
| 235 | +# ================ |
| 236 | +# |
| 237 | +# .. list-table:: |
| 238 | +# :header-rows: 1 |
| 239 | +# :widths: 15 15 25 |
| 240 | +# |
| 241 | +# * - **n_rows** |
| 242 | +# - **n_cols** |
| 243 | +# - **Calculation time** |
| 244 | +# * - 200 |
| 245 | +# - 2 |
| 246 | +# - 2"12 |
| 247 | +# * - 500 |
| 248 | +# - 2 |
| 249 | +# - 2"24 |
| 250 | +# * - 500 |
| 251 | +# - 4 |
| 252 | +# - 2"18 |
| 253 | +# * - 1000 |
| 254 | +# - 4 |
| 255 | +# - 2"48 |
| 256 | +# * - 1000 |
| 257 | +# - 6 |
| 258 | +# - 2"42 |
| 259 | +# * - 10000 |
| 260 | +# - 6 |
| 261 | +# - 20"54 |
| 262 | +# * - 10000 |
| 263 | +# - 10 |
| 264 | +# - 14"48 |
| 265 | +# * - 100000 |
| 266 | +# - 10 |
| 267 | +# - 4'51" |
| 268 | +# * - 100000 |
| 269 | +# - 15 |
| 270 | +# - 3'06" |
261 | 271 |
|
262 | 272 | # %% |
263 | 273 | # 2.1 Parameters and Hyperparameters |
|
268 | 278 | # * ``nb_projections``: Number of projections on which the test statistic is calculated. This |
269 | 279 | # parameter has the greatest influence on test calculation time. Its default value |
270 | 280 | # ``nb_projections=100``. |
271 | | -# Est-ce qu'on donne des ordres de grandeurs utiles ? J'avais un peu fait ce travail. |
272 | 281 | # |
273 | | -# * ``nb_permutation`` : Number of permutations of the projected targets. The higher is better. This |
274 | | -# parameter has little impact on calculation time. |
| 282 | +# * ``nb_permutation`` : Number of permutations of the projected targets. The higher is better. |
| 283 | +# This parameter has little impact on calculation time. |
275 | 284 | # Its default value ``nb_permutation=30``. |
276 | 285 | # |
277 | 286 | # * ``nb_trees_per_proj`` : The number of subtrees in each random forest fitted. In order to |
|
296 | 305 | # ================================================ |
297 | 306 | # |
298 | 307 | # As we have seen, Little's test only applies to quantitative data. In real life, however, it is |
299 | | -# common to have to deal with mixed data. Here's an example of how to use the PKLM test on a dataset |
300 | | -# with mixed data types. |
| 308 | +# common to have to deal with mixed data. Here's an example of how to use the PKLM test on a |
| 309 | +# dataset with mixed data types. |
301 | 310 |
|
302 | 311 | # %% |
303 | 312 | n_rows = 100 |
|
308 | 317 | modalities = ["A", "B", "C", "D"] |
309 | 318 | col4 = rng.choice(modalities, n_rows) |
310 | 319 |
|
311 | | -df = pd.DataFrame( |
312 | | - {"Numeric1": col1, "Numeric2": col2, "Boolean": col3, "Object": col4} |
313 | | -) |
| 320 | +df = pd.DataFrame({"Numeric1": col1, "Numeric2": col2, "Boolean": col3, "Object": col4}) |
314 | 321 |
|
315 | 322 | hole_gen = UniformHoleGenerator( |
316 | 323 | n_splits=1, |
|
327 | 334 | print(f"The p-value of the PKLM test is: {pklm_result:.2%}") |
328 | 335 |
|
329 | 336 | # %% |
330 | | -# To perform the PKLM test over mixed data types, non numerical features need to be encoded. The |
| 337 | +# To perform the PKLM test over mixed data types, non-numerical features need to be encoded. The |
331 | 338 | # default encoder in the :class:`~qolmat.analysis.holes_characterization.PKLMTest` class is the |
332 | 339 | # default OneHotEncoder from scikit-learn. If you wish to use an encoder adapted to your data, you |
333 | 340 | # can perform this encoding step beforehand, and then use the PKLM test. |
|
343 | 350 | # 2.3 Partial p-values |
344 | 351 | # ================================================ |
345 | 352 | # |
346 | | -# In addition, the PKLM test can be used to calculate partial p-values. We denote as many partial |
| 353 | +# In addition, the PKLM test can be used to calculate partial p-values. There are as many partial |
347 | 354 | # p-values as there are columns in the input dataframe. This “partial” p-value corresponds to the |
348 | 355 | # effect of removing the patterns induced by variable k. |
349 | 356 | # |
350 | 357 | # Let's take a look at an example of how to use this feature |
351 | 358 |
|
352 | 359 | # %% |
353 | 360 | data = rng.multivariate_normal( |
354 | | - mean=[0, 0, 0, 0], |
355 | | - cov=[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], |
356 | | - size=400, |
357 | | -) |
358 | | -df = pd.DataFrame( |
359 | | - data=data, columns=["Column 1", "Column 2", "Column 3", "Column 4"] |
| 361 | + mean=[0, 0, 0, 0], cov=[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], size=400 |
360 | 362 | ) |
| 363 | +df = pd.DataFrame(data=data, columns=["Column 1", "Column 2", "Column 3", "Column 4"]) |
361 | 364 |
|
362 | 365 | df_mask = pd.DataFrame( |
363 | 366 | { |
|
391 | 394 |
|
392 | 395 | # %% |
393 | 396 | for col_index, partial_p_v in enumerate(partial_p_values): |
394 | | - print( |
395 | | - f"The partial p-value for the column index {col_index + 1} is: {partial_p_v:.2%}" |
396 | | - ) |
| 397 | + print(f"The partial p-value for the column index {col_index + 1} is: {partial_p_v:.2%}") |
397 | 398 |
|
398 | 399 | # %% |
399 | 400 | # As a result, by removing the missing patterns induced by variable 2, the p-value rises |
|
0 commit comments