Fuzzy Regression#
This guide covers regression with Ex-Fuzzy: predicting a continuous target with rules you can read. It assumes you have met Core Concepts.
Introduction#
ex_fuzzy.BaseFuzzyRulesRegressor learns Type-1 fuzzy rules for a
numeric target using a genetic algorithm. The input partitions are fixed before
the search starts, so every membership can be precomputed once and each
candidate rule base can be scored through a vectorized NumPy or PyTorch path.
The default backend="pymoo" runs that search on the CPU. With the optional
backend="evox", population evolution and batched regression fitness run in
PyTorch on CUDA when a compatible GPU is available. EvoX automatically uses
the same PyTorch implementation on the CPU when CUDA is unavailable.
The estimator follows the scikit-learn API, so it works with cross_val_score,
Pipeline and GridSearchCV.
Basic Workflow#
Prepare
X(samples x features) and a one-dimensional numericyCreate a
BaseFuzzyRulesRegressorCall
fitwith a generation and population budgetCall
predict,scoreandprint_rules
Quick Start Example#
import numpy as np
from sklearn.datasets import make_friedman1
from sklearn.model_selection import train_test_split
from ex_fuzzy import BaseFuzzyRulesRegressor
X, y = make_friedman1(n_samples=500, n_features=5, noise=0.5, random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
regressor = BaseFuzzyRulesRegressor(nRules=20, nAnts=3, n_linguistic_variables=3)
regressor.fit(X_train, y_train, n_gen=50, pop_size=50)
print(regressor.score(X_test, y_test))
regressor.print_rules()
GPU-Accelerated Search#
Install the optional backend and select it on the estimator:
python -m pip install "ex-fuzzy[evox]"
regressor = BaseFuzzyRulesRegressor(
nRules=30,
nAnts=4,
backend="evox",
verbose=True,
)
regressor.fit(X_train, y_train, n_gen=50, pop_size=100)
After fitting, optimization_device_ is "cuda" or "cpu" and
gpu_accelerated_ records whether CUDA handled the optimization. Both crisp
and fuzzy consequents and both rule modes use the batched PyTorch fitness path.
Population and sample chunks are sized from available memory to reduce the
risk of out-of-memory errors.
Consequent Types#
Crisp Consequents (default)#
Zero-order Takagi-Sugeno. Each rule carries a number, and a prediction is the firing-strength-weighted average of the numbers of the rules that fired:
Rule 1: IF x0 IS Low AND x2 IS High THEN output = 41.8203
When to use: the default. It gives the best numeric resolution, because a consequent is a value rather than a label.
regressor = BaseFuzzyRulesRegressor(
nRules=20, nAnts=3, consequent_type="crisp"
)
Fuzzy Consequents (Mamdani Inference)#
Each rule names an output fuzzy set. Inference clips every consequent set by
its rule’s firing strength, aggregates the clipped sets with max, and
defuzzifies by taking the centroid over a discretized universe:
Rule 1: IF x0 IS Low AND x2 IS High THEN output IS Output_3
The output sets are not fixed in advance – their trapezoids are evolved alongside the rules. Each set’s four breakpoints are sorted on decoding, so every chromosome yields a well-formed trapezoid inside the target range.
When to use: when a rule should read as a complete linguistic statement, and you can trade some numeric resolution for it.
regressor = BaseFuzzyRulesRegressor(
nRules=20,
nAnts=3,
consequent_type="fuzzy",
n_output_lvs=4, # number of output sets to evolve
n_universe_points=101, # centroid integration grid
)
Rule Modes#
Additive Mode (default)#
All rules contribute to every prediction, weighted by how strongly they fire.
regressor = BaseFuzzyRulesRegressor(nRules=10, nAnts=2, rule_mode="additive")
Sufficient Mode#
Only each sample’s strongest rule fires – winner-takes-all. If even that rule
fires at or below tolerance, the sample falls back to the training-target
mean.
regressor = BaseFuzzyRulesRegressor(
nRules=10, nAnts=2, rule_mode="sufficient", tolerance=0.05
)
When to use: when you want each prediction attributable to exactly one rule. With crisp consequents the model becomes piecewise constant, since every prediction is then one rule’s consequent.
Reading the Fitted Model#
regressor.print_rules() # IF-THEN text
text = regressor.print_rules(return_rules=True)
rulebase = regressor.get_rulebase() # the rule base object
firing = rulebase.compute_rule_antecedent_memberships(X_test)
firing has shape (n_samples, n_rules) and tells you which rule drove
each prediction.
Precomputed Linguistic Variables#
Pass your own partitions to keep the input labels fixed and comparable across models:
from ex_fuzzy import utils, FUZZY_SETS
partitions = utils.construct_partitions(X_train, FUZZY_SETS.t1, n_partitions=3)
regressor = BaseFuzzyRulesRegressor(nRules=20, linguistic_variables=partitions)
Practical Notes#
The search maximizes training \(R^2\). Estimate generalization with
cross_val_score, refitting inside each fold.n_genmatters more thanpop_sizefor final quality; budget it first.nAntsis capped at the number of features. Rules may end up with fewer effective antecedents when the search selects the same feature twice.Only Type-1 fuzzy sets are supported so far.