88class NiaARM (Problem ):
99 r"""Implementation of NiaARM.
1010
11- Date:
12- 2021
13-
1411 Reference:
1512 The implementation is composed of ideas found in the following papers:
1613
17- I. Fister Jr., A. Iglesias, A. Gálvez, J. Del Ser, E. Osaba, I Fister. [Differential evolution for association rule mining using categorical and numerical attributes](http://www.iztok-jr-fister.eu/static/publications/231.pdf) In: Intelligent data engineering and automated learning - IDEAL 2018, pp. 79-88, 2018.
18-
19- I. Fister Jr., V. Podgorelec, I. Fister. Improved Nature-Inspired Algorithms for Numeric Association Rule Mining. In: Vasant P., Zelinka I., Weber GW. (eds) Intelligent Computing and Optimization. ICO 2020. Advances in Intelligent Systems and Computing, vol 1324. Springer, Cham.
14+ I. Fister Jr., A. Iglesias, A. Gálvez, J. Del Ser, E. Osaba, I Fister.
15+ [Differential evolution for association rule mining using categorical and numerical attributes]
16+ (http://www.iztok-jr-fister.eu/static/publications/231.pdf)
17+ In: Intelligent data engineering and automated learning - IDEAL 2018, pp. 79-88, 2018.
2018
21- License:
22- MIT
19+ I. Fister Jr., V. Podgorelec, I. Fister.
20+ Improved Nature-Inspired Algorithms for Numeric Association Rule Mining.
21+ In: Vasant P., Zelinka I., Weber GW. (eds) Intelligent Computing and Optimization. ICO 2020.
22+ Advances in Intelligent Systems and Computing, vol 1324. Springer, Cham.
2323
2424 Attributes:
25+ features (list[Feature]): List of features.
26+ transactions (np.ndarray): Data from transaction database.
27+ rules (list[Rule]): Mined association rules.
2528
2629 """
2730
@@ -42,30 +45,26 @@ def __init__(self, dimension, features, transactions, alpha=0.0, beta=0.0, gamma
4245 self .rules = []
4346 super ().__init__ (dimension , 0.0 , 1.0 )
4447
45- def rule_exists (self , antecedent , consequence ):
48+ def rule_exists (self , antecedent , consequent ):
4649 r"""Check if association rule already exists."""
4750 for rule in self .rules :
48- if rule .antecedent == antecedent and rule .consequence == consequence :
51+ if rule .antecedent == antecedent and rule .consequent == consequent :
4952 return True
5053 return False
5154
5255 def export_rules (self , path ):
5356 r"""Save all association rules found to csv file."""
54- try :
55- with open (path , 'w' , newline = '' ) as f :
56- writer = csv .writer (f )
57-
58- # write header
59- writer .writerow (["Antecedent" , "Consequence" , "Fitness" , "Support" , "Confidence" , "Coverage" , "Shrinkage" ])
60-
61- for rule in self .rules :
62- writer .writerow (
63- [rule .antecedent , rule .consequence , rule .fitness , rule .support , rule .confidence , rule .coverage ,
64- rule .shrink ])
65- except OSError :
66- print ('OSError:' , path )
67- else :
68- print ("Output successfully" )
57+ with open (path , 'w' , newline = '' ) as f :
58+ writer = csv .writer (f )
59+
60+ # write header
61+ writer .writerow (["Antecedent" , "consequent" , "Fitness" , "Support" , "Confidence" , "Coverage" , "Shrinkage" ])
62+
63+ for rule in self .rules :
64+ writer .writerow (
65+ [rule .antecedent , rule .consequent , rule .fitness , rule .support , rule .confidence , rule .coverage ,
66+ rule .shrink ])
67+ print (f"Rules exported to { path } " )
6968
7069 def sort_rules (self ):
7170 self .rules .sort (key = lambda x : x .fitness , reverse = True )
@@ -81,70 +80,71 @@ def _evaluate(self, sol):
8180
8281 rule = arm .build_rule (solution )
8382
84- # get antecedent and consequence of rule
83+ # get antecedent and consequent of rule
8584 antecedent = rule [:cut ]
86- consequence = rule [cut :]
85+ consequent = rule [cut :]
8786
8887 # check if rule is feasible
89- if _rule_feasible (antecedent , consequence ):
88+ if _rule_feasible (antecedent , consequent ):
9089 # get support and confidence of rule
91- support , confidence = arm .support_confidence (antecedent , consequence , self .transactions )
90+ support , confidence = arm .support_confidence (antecedent , consequent , self .transactions )
9291
9392 if self .gamma == 0.0 :
9493 shrinkage = 0
9594 else :
96- shrinkage = arm .shrinkage (antecedent , consequence )
95+ shrinkage = arm .shrinkage (antecedent , consequent )
9796
9897 if self .delta == 0.0 :
9998 coverage = 0
10099 else :
101- coverage = arm .coverage (antecedent , consequence )
100+ coverage = arm .coverage (antecedent , consequent )
102101
103102 fitness = ((self .alpha * support ) + (self .beta * confidence ) + (self .gamma * shrinkage ) +
104103 (self .delta * coverage )) / (self .alpha + self .beta + self .gamma + self .delta )
105104
106- # in case no attributes were selected for antecedent or consequence
107- if antecedent .count ("NO" ) == len (antecedent ) or consequence .count ("NO" ) == len (consequence ):
105+ # in case no attributes were selected for antecedent or consequent
106+ if antecedent .count ("NO" ) == len (antecedent ) or consequent .count ("NO" ) == len (consequent ):
108107 fitness = 0.0
109108
110109 if support > 0.0 and confidence > 0.0 :
111- antecedent , consequence = _fix_border (antecedent , consequence )
110+ antecedent , consequent = _fix_border (antecedent , consequent )
112111 # format rule; remove NO; add name of features
113- antecedent1 , consequence1 = arm .format_rules (antecedent , consequence )
112+ antecedent1 , consequent1 = arm .format_rules (antecedent , consequent )
114113
115114 # save feasible rule
116- if not self .rule_exists (antecedent1 , consequence1 ):
117- self .rules .append (Rule (antecedent1 , consequence1 , fitness , support , confidence , coverage , shrinkage ))
115+ if not self .rule_exists (antecedent1 , consequent1 ):
116+ self .rules .append (
117+ Rule (antecedent1 , consequent1 , fitness , support , confidence , coverage , shrinkage ))
118118
119119 if fitness > self .best_fitness :
120120 self .best_fitness = fitness
121- print (f'Fitness: { fitness } , Support: { support } , Confidence:{ confidence } , Coverage:{ coverage } , Shrinkage:{ shrinkage } ' )
121+ print (f'Fitness: { fitness } , Support: { support } , Confidence:{ confidence } , Coverage:{ coverage } , '
122+ f'Shrinkage:{ shrinkage } ' )
122123 return fitness
123124 else :
124125 return - 1.0
125126
126127
127- def _fix_border (antecedent , consequence ):
128+ def _fix_border (antecedent , consequent ):
128129 r"""In case lower and upper bounds of interval are the same.
129130 We need this in order to provide clean output.
130131
131132 Arguments:
132133 antecedent (np.ndarray): .
133- consequence (np.ndarray): .
134+ consequent (np.ndarray): .
134135
135136 Returns:
136137 antecedent (array):
137- consequence (array):
138+ consequent (array):
138139 """
139-
140140 for i in range (len (antecedent )):
141141 if len (antecedent [i ]) > 1 :
142142 if antecedent [i ][0 ] == antecedent [i ][1 ]:
143143 antecedent [i ] = antecedent [i ][0 ]
144144
145- for i in range (len (consequence )):
146- if len (consequence [i ]) > 1 :
147- if consequence [i ][0 ] == consequence [i ][1 ]:
148- consequence [i ] = consequence [i ][0 ]
145+ for i in range (len (consequent )):
146+ if len (consequent [i ]) > 1 :
147+ if consequent [i ][0 ] == consequent [i ][1 ]:
148+ consequent [i ] = consequent [i ][0 ]
149149
150- return antecedent , consequence
150+ return antecedent , consequent
0 commit comments