@@ -45,9 +45,7 @@ def __init__(self, random_state: RandomSetting = None):
4545 self .rng = sku .check_random_state (random_state )
4646
4747 @abstractmethod
48- def test (
49- self , df : Union [pd .DataFrame , np .ndarray ]
50- ) -> Union [float , Tuple [float , List [float ]]]:
48+ def test (self , df : Union [pd .DataFrame , np .ndarray ]) -> Union [float , Tuple [float , List [float ]]]:
5149 """Perform the MCAR test on the input data.
5250
5351 Parameters
@@ -99,8 +97,7 @@ def __init__(
9997 super ().__init__ ()
10098 if imputer and imputer .model != "multinormal" :
10199 raise AttributeError (
102- "The ImputerEM model must be 'multinormal' "
103- "to use the Little's test"
100+ "The ImputerEM model must be 'multinormal' " "to use the Little's test"
104101 )
105102 self .imputer = imputer
106103 self .random_state = random_state
@@ -131,22 +128,16 @@ def test(self, df: pd.DataFrame) -> float:
131128 # Iterate over the patterns
132129
133130 df_nan = df .notna ()
134- for tup_pattern , df_nan_pattern in df_nan .groupby (
135- df_nan .columns .tolist ()
136- ):
131+ for tup_pattern , df_nan_pattern in df_nan .groupby (df_nan .columns .tolist ()):
137132 n_rows_pattern , _ = df_nan_pattern .shape
138133 ind_pattern = df_nan_pattern .index
139134 df_pattern = df .loc [ind_pattern , list (tup_pattern )]
140135 obs_mean = df_pattern .mean ().to_numpy ()
141136
142137 diff_means = obs_mean - ml_means [list (tup_pattern )]
143- inv_sigma_pattern = np .linalg .inv (
144- ml_cov [:, tup_pattern ][tup_pattern , :]
145- )
138+ inv_sigma_pattern = np .linalg .inv (ml_cov [:, tup_pattern ][tup_pattern , :])
146139
147- d0 += n_rows_pattern * np .dot (
148- np .dot (diff_means , inv_sigma_pattern ), diff_means .T
149- )
140+ d0 += n_rows_pattern * np .dot (np .dot (diff_means , inv_sigma_pattern ), diff_means .T )
150141 degree_f += tup_pattern .count (True )
151142
152143 return 1 - float (chi2 .cdf (d0 , degree_f ))
@@ -242,9 +233,7 @@ def _encode_dataframe(self, df: pd.DataFrame) -> np.ndarray:
242233
243234 return self .encoder .fit_transform (df )
244235
245- def _pklm_preprocessing (
246- self , X : Union [pd .DataFrame , np .ndarray ]
247- ) -> np .ndarray :
236+ def _pklm_preprocessing (self , X : Union [pd .DataFrame , np .ndarray ]) -> np .ndarray :
248237 """Preprocess the input DataFrame or ndarray for further processing.
249238
250239 Parameters
@@ -295,9 +284,7 @@ def _get_max_draw(p: int) -> int:
295284 """
296285 return p * (2 ** (p - 1 ) - 1 )
297286
298- def _draw_features_and_target_indexes (
299- self , X : np .ndarray
300- ) -> Tuple [List [int ], int ]:
287+ def _draw_features_and_target_indexes (self , X : np .ndarray ) -> Tuple [List [int ], int ]:
301288 """Randomly select features and a target from the dataframe.
302289
303290 This corresponds to the Ai and Bi projections of the paper.
@@ -320,9 +307,7 @@ def _draw_features_and_target_indexes(
320307 return features_idx .tolist (), target_idx
321308
322309 @staticmethod
323- def _check_draw (
324- X : np .ndarray , features_idx : List [int ], target_idx : int
325- ) -> bool :
310+ def _check_draw (X : np .ndarray , features_idx : List [int ], target_idx : int ) -> bool :
326311 """Check if the drawn features and target are valid.
327312
328313 Here we check
@@ -344,16 +329,12 @@ def _check_draw(
344329 True if the draw is valid, False otherwise.
345330
346331 """
347- target_values = X [~ np .isnan (X [:, features_idx ]).any (axis = 1 )][
348- :, target_idx
349- ]
332+ target_values = X [~ np .isnan (X [:, features_idx ]).any (axis = 1 )][:, target_idx ]
350333 is_nan = np .isnan (target_values ).any ()
351334 is_distinct_values = (~ np .isnan (target_values )).any ()
352335 return is_nan and is_distinct_values
353336
354- def _generate_label_feature_combinations (
355- self , X : np .ndarray
356- ) -> List [Tuple [List [int ], int ]]:
337+ def _generate_label_feature_combinations (self , X : np .ndarray ) -> List [Tuple [List [int ], int ]]:
357338 """Generate all valid combinations of features and labels.
358339
359340 Parameters
@@ -400,9 +381,7 @@ def _draw_projection(self, X: np.ndarray) -> Tuple[List[int], int]:
400381 """
401382 is_checked = False
402383 while not is_checked :
403- features_idx , target_idx = self ._draw_features_and_target_indexes (
404- X
405- )
384+ features_idx , target_idx = self ._draw_features_and_target_indexes (X )
406385 is_checked = self ._check_draw (X , features_idx , target_idx )
407386 return features_idx , target_idx
408387
@@ -434,13 +413,9 @@ def _build_dataset(
434413 the target column.
435414
436415 """
437- X_features = X [~ np .isnan (X [:, features_idx ]).any (axis = 1 )][
438- :, features_idx
439- ]
416+ X_features = X [~ np .isnan (X [:, features_idx ]).any (axis = 1 )][:, features_idx ]
440417 y = np .where (
441- np .isnan (
442- X [~ np .isnan (X [:, features_idx ]).any (axis = 1 )][:, target_idx ]
443- ),
418+ np .isnan (X [~ np .isnan (X [:, features_idx ]).any (axis = 1 )][:, target_idx ]),
444419 1 ,
445420 0 ,
446421 )
@@ -479,9 +454,7 @@ def _build_label(
479454 """
480455 return perm [~ np .isnan (X [:, features_idx ]).any (axis = 1 ), target_idx ]
481456
482- def _get_oob_probabilities (
483- self , X : np .ndarray , y : np .ndarray
484- ) -> np .ndarray :
457+ def _get_oob_probabilities (self , X : np .ndarray , y : np .ndarray ) -> np .ndarray :
485458 """Retrieve out-of-bag probabilities.
486459
487460 Train a RandomForestClassifier and retrieves out-of-bag (OOB)
@@ -547,26 +520,14 @@ def _U_hat(oob_probabilities: np.ndarray, labels: np.ndarray) -> float:
547520 if unique_labels .shape [0 ] == 1 :
548521 if unique_labels [0 ] == 0 :
549522 n0 = labels .shape [0 ]
550- return (
551- np .log (p0_0 / (1 - p0_0 )).sum () / n0
552- - np .log (p1_0 / (1 - p1_0 )).sum () / n0
553- )
523+ return np .log (p0_0 / (1 - p0_0 )).sum () / n0 - np .log (p1_0 / (1 - p1_0 )).sum () / n0
554524 else :
555525 n1 = labels .shape [0 ]
556- return (
557- np .log (p1_1 / (1 - p1_1 )).sum () / n1
558- - np .log (p0_1 / (1 - p0_1 )).sum () / n1
559- )
526+ return np .log (p1_1 / (1 - p1_1 )).sum () / n1 - np .log (p0_1 / (1 - p0_1 )).sum () / n1
560527
561528 n0 , n1 = label_matrix .sum (axis = 0 )
562- u_0 = (
563- np .log (p0_0 / (1 - p0_0 )).sum () / n0
564- - np .log (p0_1 / (1 - p0_1 )).sum () / n1
565- )
566- u_1 = (
567- np .log (p1_1 / (1 - p1_1 )).sum () / n1
568- - np .log (p1_0 / (1 - p1_0 )).sum () / n0
569- )
529+ u_0 = np .log (p0_0 / (1 - p0_0 )).sum () / n0 - np .log (p0_1 / (1 - p0_1 )).sum () / n1
530+ u_1 = np .log (p1_1 / (1 - p1_1 )).sum () / n1 - np .log (p1_0 / (1 - p1_0 )).sum () / n0
570531
571532 return u_0 + u_1
572533
@@ -708,9 +669,7 @@ def _compute_partial_p_value(
708669
709670 return p_v_k / (self .nb_permutation + 1 )
710671
711- def test (
712- self , X : Union [pd .DataFrame , np .ndarray ]
713- ) -> Union [float , Tuple [float , List [float ]]]:
672+ def test (self , X : Union [pd .DataFrame , np .ndarray ]) -> Union [float , Tuple [float , List [float ]]]:
714673 """Apply the PKLM test over a real dataset.
715674
716675 Parameters
@@ -733,21 +692,15 @@ def test(
733692 if self ._get_max_draw (n_cols ) <= self .nb_projections_threshold :
734693 list_proj = self ._generate_label_feature_combinations (X )
735694 else :
736- list_proj = [
737- self ._draw_projection (X ) for _ in range (self .nb_projections )
738- ]
695+ list_proj = [self ._draw_projection (X ) for _ in range (self .nb_projections )]
739696
740697 M = np .isnan (X ).astype (int )
741- list_perm = [
742- self .rng .permutation (M ) for _ in range (self .nb_permutation )
743- ]
698+ list_perm = [self .rng .permutation (M ) for _ in range (self .nb_permutation )]
744699 U = 0.0
745700 list_U_sigma = [0.0 for _ in range (self .nb_permutation )]
746701
747702 parallel_results = Parallel (n_jobs = - 1 )(
748- delayed (self ._parallel_process_projection )(
749- X , list_perm , features_idx , target_idx
750- )
703+ delayed (self ._parallel_process_projection )(X , list_perm , features_idx , target_idx )
751704 for features_idx , target_idx in list_proj
752705 )
753706
@@ -769,14 +722,9 @@ def test(
769722 return p_value
770723 else :
771724 B = self ._build_B (list_proj , n_cols )
772- U_matrix = np .array (
773- [np .atleast_1d (item [0 ]) for item in parallel_results ]
774- )
775- U_sigma = np .array (
776- [np .atleast_1d (item [1 ]) for item in parallel_results ]
777- )
725+ U_matrix = np .array ([np .atleast_1d (item [0 ]) for item in parallel_results ])
726+ U_sigma = np .array ([np .atleast_1d (item [1 ]) for item in parallel_results ])
778727 p_values = [
779- self ._compute_partial_p_value (B , U_matrix , U_sigma , k )
780- for k in range (n_cols )
728+ self ._compute_partial_p_value (B , U_matrix , U_sigma , k ) for k in range (n_cols )
781729 ]
782730 return p_value , p_values
0 commit comments