Skip to content

Commit c2a0485

Browse files
committed
The inner ML algorithm is now sent as an argument
1 parent 2b481cf commit c2a0485

8 files changed

+45
-39
lines changed

Arguments.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
from sys import argv
22

3+
from m3gp.MahalanobisDistanceClassifier import MahalanobisDistanceClassifier
4+
from sklearn.ensemble import RandomForestClassifier
5+
from sklearn.tree import DecisionTreeRegressor
6+
37
#
48
# By using this file, you are agreeing to this product's EULA
59
#
610
# This product can be obtained in https://github.com/jespb/Python-M3GP
711
#
8-
# Copyright ©2019-2022 J. E. Batista
12+
# Copyright ©2019-2025 J. E. Batista
913
#
1014

1115

@@ -58,7 +62,8 @@
5862
RANDOM_STATE = 42
5963

6064
# Models wrapped by the M3GP models
61-
MODEL_NAME = ["MahalanobisDistanceClassifier", "RandomForestClassifier", "DecisionTreeRegressor"][0]
65+
MODEL = [MahalanobisDistanceClassifier(), RandomForestClassifier(max_depth=6), DecisionTreeRegressor(max_depth=6)][0]
66+
MODEL_NAME = MODEL.__class__.__name__
6267

6368
# Fitness used by the M3GP models
6469
FITNESS_TYPE = ["Accuracy", "MSE", "WAF", "2FOLD"][0]

Main_M3GP_classification_example.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import pandas
22

33
from m3gp.M3GP import M3GP
4+
from sklearn.ensemble import RandomForestClassifier
45

56
from sklearn.model_selection import train_test_split
67

@@ -17,7 +18,7 @@
1718
#
1819
# This product can be obtained in https://github.com/jespb/Python-M3GP
1920
#
20-
# Copyright ©2019-2021 J. E. Batista
21+
# Copyright ©2019-2025 J. E. Batista
2122
#
2223

2324

@@ -33,7 +34,7 @@
3334
train_size=0.7, random_state = 42, stratify = ds[class_header])
3435

3536
# Train a model
36-
m3gp = M3GP()
37+
m3gp = M3GP(model_class=RandomForestClassifier(max_depth=6), fitnessType="2FOLD")
3738
m3gp.fit(Tr_X, Tr_Y)
3839

3940
# Predict test results

Main_M3GP_regression_example.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
from sklearn.metrics import mean_squared_error
88

9+
10+
from sklearn.tree import DecisionTreeRegressor
11+
912
import warnings
1013

1114
warnings.filterwarnings("ignore", category=FutureWarning,
@@ -17,12 +20,12 @@
1720
#
1821
# This product can be obtained in https://github.com/jespb/Python-M3GP
1922
#
20-
# Copyright ©2019-2021 J. E. Batista
23+
# Copyright ©2019-2025 J. E. Batista
2124
#
2225

2326

2427

25-
filename= "boom_bikes.csv"
28+
filename= "heart.csv"
2629

2730
# Open the dataset
2831
ds = pandas.read_csv("datasets/"+filename)
@@ -33,7 +36,7 @@
3336
train_size=0.7, random_state = 42)
3437

3538
# Train a model
36-
m3gp = M3GP(max_generation=20, model_name="DecisionTreeRegressor", fitnessType="MSE",random_state=21)
39+
m3gp = M3GP(max_generation=20, model_class=DecisionTreeRegressor(max_depth=5), fitnessType="MSE",random_state=21)
3740
m3gp.fit(Tr_X, Tr_Y, Te_X, Te_Y)
3841

3942
# Predict test results

Main_M3GP_standalone.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#
2222
# This product can be obtained in https://github.com/jespb/Python-M3GP
2323
#
24-
# Copyright ©2019-2024 J. E. Batista
24+
# Copyright ©2019-2025 J. E. Batista
2525
#
2626

2727

@@ -53,7 +53,7 @@ def run(r,dataset):
5353

5454
# Train a model
5555
m3gp = M3GP(OPERATORS, MAX_DEPTH, POPULATION_SIZE, MAX_GENERATION, TOURNAMENT_SIZE,
56-
ELITISM_SIZE, LIMIT_DEPTH, DIM_MIN, DIM_MAX, THREADS, r, VERBOSE, MODEL_NAME, FITNESS_TYPE)
56+
ELITISM_SIZE, LIMIT_DEPTH, DIM_MIN, DIM_MAX, THREADS, r, VERBOSE, MODEL, FITNESS_TYPE)
5757
m3gp.fit(Tr_X, Tr_Y, Te_X, Te_Y)
5858

5959

m3gp/GeneticOperators.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#
77
# This product can be obtained in https://github.com/jespb/Python-M3GP
88
#
9-
# Copyright ©2019-2022 J. E. Batista
9+
# Copyright ©2019-2025 J. E. Batista
1010
#
1111

1212

@@ -97,7 +97,7 @@ def STXO(rng, population, tournament_size):
9797

9898
ret = []
9999
for d in [d1,d2]:
100-
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_name, ind1.fitnessType)
100+
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_class, ind1.fitnessType)
101101
i.copy(d)
102102
ret.append(i)
103103
return ret
@@ -126,7 +126,7 @@ def M3XO(rng, population, tournament_size):
126126

127127
ret = []
128128
for d in [d1,d2]:
129-
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_name, ind1.fitnessType)
129+
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_class, ind1.fitnessType)
130130
i.copy(d)
131131
ret.append(i)
132132
return ret
@@ -149,7 +149,7 @@ def STMUT(rng, population, tournament_size):
149149

150150

151151
ret = []
152-
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_name, ind1.fitnessType)
152+
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_class, ind1.fitnessType)
153153
i.copy(d1)
154154
ret.append(i)
155155
return ret
@@ -171,7 +171,7 @@ def M3ADD(rng, population, tournament_size, dim_max):
171171
n.create(rng, ind1.operators, ind1.terminals, ind1.max_depth)
172172
d1.append(n)
173173

174-
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_name, ind1.fitnessType)
174+
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_class, ind1.fitnessType)
175175
i.copy(d1)
176176
ret.append(i)
177177

@@ -193,7 +193,7 @@ def M3REM(rng, population, tournament_size, dim_min):
193193
r1 = rng.randint(0,len(d1)-1)
194194
d1.pop(r1)
195195

196-
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_name, ind1.fitnessType)
196+
i = Individual(ind1.operators, ind1.terminals, ind1.max_depth, ind1.model_class, ind1.fitnessType)
197197
i.copy(d1)
198198
ret.append(i)
199199

m3gp/Individual.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
from sklearn.tree import DecisionTreeRegressor
21
from .Node import Node
3-
from .MahalanobisDistanceClassifier import MahalanobisDistanceClassifier
4-
from sklearn.ensemble import RandomForestClassifier
52

63
import pandas as pd
74

5+
from copy import deepcopy
6+
87
from sklearn.metrics import accuracy_score, f1_score, cohen_kappa_score, mean_squared_error
98

109

@@ -13,7 +12,7 @@
1312
#
1413
# This product can be obtained in https://github.com/jespb/Python-M3GP
1514
#
16-
# Copyright ©2019-2022 J. E. Batista
15+
# Copyright ©2019-2025 J. E. Batista
1716
#
1817

1918
class Individual:
@@ -34,11 +33,11 @@ class Individual:
3433

3534
model = None
3635

37-
def __init__(self, operators, terminals, max_depth, model_name="MahalanobisDistanceClassifier", fitnessType="Accuracy"):
36+
def __init__(self, operators, terminals, max_depth, model_class=None, fitnessType="Accuracy"):
3837
self.operators = operators
3938
self.terminals = terminals
4039
self.max_depth = max_depth
41-
self.model_name = model_name
40+
self.model_class = model_class
4241
self.fitnessType = fitnessType
4342

4443
def create(self,rng, n_dims=1):
@@ -74,12 +73,7 @@ def __str__(self):
7473

7574

7675
def createModel(self):
77-
if self.model_name == "MahalanobisDistanceClassifier":
78-
return MahalanobisDistanceClassifier()
79-
elif self.model_name == "RandomForestClassifier":
80-
return RandomForestClassifier(random_state = 42, max_depth=6)
81-
elif self.model_name == "DecisionTreeRegressor":
82-
return DecisionTreeRegressor(random_state = 42, max_depth=6)
76+
return deepcopy(self.model_class)
8377

8478
def fit(self, Tr_x, Tr_y):
8579
'''
@@ -150,7 +144,7 @@ def getFitness(self, tr_x = None, tr_y = None):
150144
if self.fitnessType == "MSE":
151145
self.fit(self.training_X, self.training_Y)
152146
self.getTrainingPredictions()
153-
mse = -1 * mean_squared_error(self.trainingPredictions, self.training_Y)
147+
mse = float(-1 * mean_squared_error(self.trainingPredictions, self.training_Y))
154148
self.fitness = mse
155149

156150
if self.fitnessType == "WAF":
@@ -319,15 +313,15 @@ def prun(self,min_dim=1,simp=False):
319313

320314
dup = self.dimensions[:]
321315
i = 0
322-
ind = Individual(self.operators, self.terminals, self.max_depth, self.model_name, self.fitnessType)
316+
ind = Individual(self.operators, self.terminals, self.max_depth, self.model_class, self.fitnessType)
323317
ind.copy(dup)
324318

325319
ind.fit(self.training_X, self.training_Y)
326320

327321
while i < len(dup) and len(dup) > min_dim:
328322
dup2 = dup[:]
329323
dup2.pop(i)
330-
ind2 = Individual(self.operators, self.terminals, self.max_depth, self.model_name, self.fitnessType)
324+
ind2 = Individual(self.operators, self.terminals, self.max_depth, self.model_class, self.fitnessType)
331325
ind2.copy(dup2)
332326
ind2.fit(self.training_X, self.training_Y)
333327

m3gp/M3GP.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
import multiprocessing as mp
44
import time
55

6+
from .MahalanobisDistanceClassifier import MahalanobisDistanceClassifier
7+
68
from random import Random
79

810
#
911
# By using this file, you are agreeing to this product's EULA
1012
#
1113
# This product can be obtained in https://github.com/jespb/Python-M3GP
1214
#
13-
# Copyright ©2019-2022 J. E. Batista
15+
# Copyright ©2019-2025 J. E. Batista
1416
#
1517

1618
class ClassifierNotTrainedError(Exception):
@@ -38,7 +40,7 @@ class M3GP:
3840
dim_min = None
3941
dim_max = None
4042

41-
model_name = None
43+
model_class = None
4244
fitnessType = None
4345

4446
verbose = None
@@ -73,7 +75,7 @@ def checkIfTrained(self):
7375

7476
def __init__(self, operators=[("+",2),("-",2),("*",2),("/",2)], max_initial_depth = 6, population_size = 500,
7577
max_generation = 100, tournament_size = 5, elitism_size = 1, max_depth = 17,
76-
dim_min = 1, dim_max = 9999, threads=1, random_state = 42, verbose = True, model_name="MahalanobisDistanceClassifier", fitnessType="Accuracy"):
78+
dim_min = 1, dim_max = 9999, threads=1, random_state = 42, verbose = True, model_class=None, fitnessType="Accuracy"):
7779

7880
if sum( [0 if op in [("+",2),("-",2),("*",2),("/",2)] else 0 for op in operators ] ) > 0:
7981
print( "[Warning] Some of the following operators may not be supported:", operators)
@@ -93,7 +95,9 @@ def __init__(self, operators=[("+",2),("-",2),("*",2),("/",2)], max_initial_dept
9395
self.dim_min = max(1, dim_min)
9496
self.dim_max = max(1, dim_max)
9597

96-
self.model_name = model_name
98+
self.model_class = model_class
99+
if self.model_class is None:
100+
self.model_class = MahalanobisDistanceClassifier()
97101
self.fitnessType = fitnessType
98102

99103
self.verbose = verbose
@@ -191,7 +195,7 @@ def fit(self,Tr_x, Tr_y, Te_x = None, Te_y = None):
191195
print(" > Max Depth: "+str(self.max_depth))
192196
print(" > Minimum Dimensions: "+str(self.dim_min))
193197
print(" > Maximum Dimensions: "+str(self.dim_max))
194-
print(" > Wrapped Model: "+self.model_name)
198+
print(" > Wrapped Model: "+self.model_class.__class__.__name__)
195199
print(" > Fitness Type: "+self.fitnessType)
196200
print(" > Threads: "+str(self.threads))
197201
print()
@@ -206,12 +210,13 @@ def fit(self,Tr_x, Tr_y, Te_x = None, Te_y = None):
206210
self.population = []
207211

208212
while len(self.population) < self.population_size:
209-
ind = Individual(self.operators, self.terminals, self.max_depth, self.model_name, self.fitnessType)
213+
ind = Individual(self.operators, self.terminals, self.max_depth, self.model_class, self.fitnessType)
210214
ind.create(self.rng, n_dims = self.dim_min)
211215
self.population.append(ind)
212216

213217
self.bestIndividual = self.population[0]
214218
self.bestIndividual.fit(self.Tr_x, self.Tr_y)
219+
self.bestIndividual.getFitness()
215220

216221
if not self.Te_x is None:
217222
self.trainingAccuracyOverTime = []

m3gp/MahalanobisDistanceClassifier.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#
66
# This product can be obtained in https://github.com/jespb/Python-M3GP
77
#
8-
# Copyright ©2019-2022 J. E. Batista
8+
# Copyright ©2019-2025 J. E. Batista
99
#
1010

1111
#
@@ -77,8 +77,6 @@ def fit(self,X,Y):
7777
'''
7878
Calculates the class clusters in the output space.
7979
'''
80-
if self.invCovarianceMatrix != None:
81-
return
8280

8381
X = [ list(sample) for sample in X.iloc ]
8482
Y = list(Y)

0 commit comments

Comments
 (0)