trevorstephens / gplearn

Genetic Programming in Python, with a scikit-learn inspired API
http://gplearn.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
1.56k stars 274 forks source link

Use of raw_fitness vs. penalized fitness #284

Closed SHWeasel closed 1 year ago

SHWeasel commented 1 year ago

Hi all,

It is my first posting, so I hope all is fine with the contrib guidelines in my post.

At first, many thinks for the library! I am currently writing my master thesis about symbolic regression boosting with gplearn and during the different tests I noticed an unexpected (and I maybe unintended) behavior.

My problem is the use of the raw_fitness and the fitness with penalty based on the parsimony_coefficient. When the program runs, it seems like the evolution process is based on the penalized fitness. So basically higher parsimony leads to lower program lengths. So far, so fine, all expected.

But the documentation with verbose = 1 prints out the raw_fitness and (and that is the main problem) the stopping_criteria also goes on the raw_fitness and not the penalized fitness. This leads to the effect that I cannot control the bloat via the parsimony properly.

One can see it also in the example from the docs. (https://gplearn.readthedocs.io/en/stable/examples.html)

est_gp = SymbolicRegressor(population_size=5000, generations=20, stopping_criteria=0.01, p_crossover=0.7, p_subtree_mutation=0.1, p_hoist_mutation=0.05, p_point_mutation=0.1, max_samples=0.9, verbose=1, parsimony_coefficient=0.01, random_state=0) est_gp.fit(X_train, y_train)

Since the raw_fitness is the 6th generation is 0.0007, which is below the stopping criteria of 0.01, the program stops.

print(est_gp._program.rawfitness) 0.000781

But the penalized fitness is: print(est_gp.program.fitness) 0.110781 ...and therefore above 0.01.

So the program could even have a length of 50, it is still stopped, based on the satisfied stopping_criteria, because of the checks on the raw_fitness. This makes it difficult to control the bloat in combination with a stopping_criteria.

Long story short, is this intended? I was surprised to see that the evolution works with penalized fitness, but the stopping_criteria and the verbose prints use the raw_fitness instead. I thought it all goes for the penalized fitness. But maybe I also missed something.

Used Versions: NumPy 1.23.5 SciPy 1.9.3 Scikit-Learn 1.1.3 Joblib 1.2.0 gplearn 0.4.2

Many thanks in advance :)

trevorstephens commented 1 year ago

Hey this is all expected and described in the docs: https://gplearn.readthedocs.io/en/stable/intro.html#bloat

Bloat is controlled during selection with the penalised fitness, the stopping criteria is based on the performance of the winning program on the data as this is what you actually care about in the end.

SHWeasel commented 1 year ago

Ahh, missed that in the docs, sorry. Thanks for the swift reply!

BR