Rule learning¶
Learning a rule base from data (Wang-Mendel)¶
wang_mendel generates a Mamdani rule base from
data: each sample becomes one rule (picking the highest-membership term per
variable), and antecedent conflicts are resolved by rule degree.
import numpy as np
import fuzzytool as fz
X = np.random.default_rng(0).uniform(0, 10, size=(300, 2))
y = (X[:, 0] + X[:, 1]) / 2
a = fz.Variable("a", (0, 10), terms=["lo", "mid", "hi"])
b = fz.Variable("b", (0, 10), terms=["lo", "mid", "hi"])
out = fz.Variable("out", (0, 10), terms=["lo", "mid", "hi"])
sys = fz.wang_mendel(X, y, [a, b], out) # a ready-to-use Mamdani system
sys(a=8, b=7) # -> 5.88 (learned system approximates the mean (a + b) / 2)
The input variables supply the partition; the learned system is a plain
Mamdani, so it also supports batch predict and
serialization.
use_weights=True gives each rule a weight equal to its normalized degree, so
rules backed by strongly-matching samples outweigh those scraped from the edge
of a partition.
Audit what you learn
Learned rule bases emit one rule per occupied partition cell, and a good
share of those turn out to be duplicates or dead. Run
audit and prune before shipping
one.
Classification (Chi)¶
chi is the classification counterpart of Wang-Mendel:
same antecedents, class labels as consequents, plus a certainty factor per rule.
See Fuzzy classification.
Scatter partition: one rule per cluster¶
A grid partition needs a term per variable per rule, so the rule count grows with the number of inputs. A scatter partition lets clustering find where the data actually is, and turns each cluster into one rule — the rule count follows the structure of the data instead.
subtractive_clustering (Chiu, 1994)
finds the centers without being told how many there are:
chiu_tsk builds a complete Takagi-Sugeno system
from those centers, fitting the consequents by least squares:
sys = fz.chiu_tsk(X, y, radii=0.4, names=["a", "b"])
sys(a=8, b=7)
sys.variables_ # the Gaussian partition it generated
cmeans_tsk does the same from a fuzzy c-means
partition, when you would rather choose the number of rules directly:
Both return an ordinary TSK system — explainable, auditable, serializable.
Pass ridge=1e-6 when clusters overlap heavily and the least-squares fit is
ill-conditioned, and order=0 for constant instead of affine consequents.
Tsukamoto inference¶
Tsukamoto consequents are
monotonic membership functions; a rule firing with strength w outputs the
value where its consequent reaches w (its inverse), and the system returns the
firing-weighted average — no defuzzification.
import fuzzytool as fz
x = fz.Variable("x", (0, 10), terms=["lo", "hi"])
sys = fz.Tsukamoto()
sys.rule(x["lo"], fz.ramp_down(0, 30)) # monotonic consequents only
sys.rule(x["hi"], fz.ramp_up(0, 30))
sys(x=7) # -> 21.0
Use ramp_up,
ramp_down, or
sigmoid — each exposes the inverse Tsukamoto
needs.