22Module to generate diverse counterfactual explanations based on genetic algorithm
33This code is similar to 'GeCo: Quality Counterfactual Explanations in Real Time': https://arxiv.org/pdf/2101.01292.pdf
44"""
5- import copy
6- import random
7- import timeit
8-
5+ from dice_ml .explainer_interfaces .explainer_base import ExplainerBase
96import numpy as np
107import pandas as pd
8+ import random
9+ import timeit
10+ import copy
1111from sklearn .preprocessing import LabelEncoder
1212
1313from dice_ml import diverse_counterfactuals as exp
1414from dice_ml .constants import ModelTypes
15- from dice_ml .explainer_interfaces .explainer_base import ExplainerBase
1615
1716
1817class DiceGenetic (ExplainerBase ):
@@ -116,9 +115,8 @@ def do_random_init(self, num_inits, features_to_vary, query_instance, desired_cl
116115 def do_KD_init (self , features_to_vary , query_instance , cfs , desired_class , desired_range ):
117116 cfs = self .label_encode (cfs )
118117 cfs = cfs .reset_index (drop = True )
119-
120- self .cfs = np .zeros ((self .population_size , self .data_interface .number_of_features ))
121- for kx in range (self .population_size ):
118+ row = []
119+ for kx in range (self .population_size * 5 ):
122120 if kx >= len (cfs ):
123121 break
124122 one_init = np .zeros (self .data_interface .number_of_features )
@@ -143,16 +141,21 @@ def do_KD_init(self, features_to_vary, query_instance, cfs, desired_class, desir
143141 one_init [jx ] = query_instance [jx ]
144142 else :
145143 one_init [jx ] = np .random .choice (self .feature_range [feature ])
146- self .cfs [kx ] = one_init
144+ t = tuple (one_init )
145+ if t not in row :
146+ row .append (t )
147+ if len (row ) == self .population_size :
148+ break
147149 kx += 1
150+ self .cfs = np .array (row )
148151
149- new_array = [ tuple ( row ) for row in self .cfs ]
150- uniques = np . unique ( new_array , axis = 0 )
151-
152- if len ( uniques ) != self . population_size :
152+ #if len(self.cfs) > self.population_size:
153+ # pass
154+ if len ( self . cfs ) != self . population_size :
155+ print ( "Pericolo Loop infinito....!!!!" )
153156 remaining_cfs = self .do_random_init (
154- self .population_size - len (uniques ), features_to_vary , query_instance , desired_class , desired_range )
155- self .cfs = np .concatenate ([uniques , remaining_cfs ])
157+ self .population_size - len (self . cfs ), features_to_vary , query_instance , desired_class , desired_range )
158+ self .cfs = np .concatenate ([self . cfs , remaining_cfs ])
156159
157160 def do_cf_initializations (self , total_CFs , initialization , algorithm , features_to_vary , desired_range ,
158161 desired_class ,
@@ -260,7 +263,7 @@ def _generate_counterfactuals(self, query_instance, total_CFs, initialization="k
260263 (see diverse_counterfactuals.py).
261264 """
262265
263- self .population_size = 10 * total_CFs
266+ self .population_size = 3 * total_CFs
264267
265268 self .start_time = timeit .default_timer ()
266269
@@ -514,6 +517,9 @@ def find_counterfactuals(self, query_instance, desired_range, desired_class,
514517 if len (self .final_cfs ) == self .total_CFs :
515518 print ('Diverse Counterfactuals found! total time taken: %02d' %
516519 m , 'min %02d' % s , 'sec' )
520+ elif len (self .final_cfs ) == 0 :
521+ print ('No Counterfactuals found for the given configuration, perhaps try with different parameters...' ,
522+ '; total time taken: %02d' % m , 'min %02d' % s , 'sec' )
517523 else :
518524 print ('Only %d (required %d) ' % (len (self .final_cfs ), self .total_CFs ),
519525 'Diverse Counterfactuals found for the given configuation, perhaps ' ,
0 commit comments