🐍 Iris sample#

This notebook walks through building a formal concept lattice from the Iris dataset using GALACTIC.

Creating item universe#

Load the Iris CSV dataset and wrap its rows into an item universe used by the later algebraic steps.

[1]:
from pathlib import Path
from galactic.io.data.core import DataFileRegistry
[2]:
path = Path("iris.csv")
dataset = DataFileRegistry().load(path)
[3]:
from galactic.algebras.concept.core import ItemUniverse
[4]:
item_universe = ItemUniverse(dataset)
len(item_universe)
[4]:
150

Creating characteristics#

Define numerical and categorical characteristics that represent the Iris measurements and species label.

[5]:
from galactic.algebras.convex.characteristics.core import Component, Number, String
[6]:
sepal_length = Number(
    components=(Component(expr='"sepal length"'),),
    name="sepal_length",
    cache=150,
)
sepal_width = Number(
    components=(Component(expr='"sepal width"'),),
    name="sepal_width",
    cache=150,
)
petal_length = Number(
    components=(Component(expr='"petal length"'),),
    name="petal_length",
    cache=150,
)
petal_width = Number(
    components=(Component(expr='"petal width"'),),
    name="petal_width",
    cache=150,
)
klass = String(
    components=(Component(expr="class"),),
    name="class",
)

Creating predicate universe#

Build the predicate universe by pairing each characteristic with the corresponding numerical or categorical description.

[7]:
from galactic.algebras.convex.descriptions.numerical.hull.core import (
    NumericalDescription,
)
from galactic.algebras.convex.descriptions.category.basic.core import (
    CategoryDescription,
)
from galactic.algebras.convex.descriptions.core import (
    PredicateUniverse,
)
[8]:
sepal_length_description = NumericalDescription(space=(sepal_length,))
sepal_width_description = NumericalDescription(space=(sepal_width,))
petal_length_description = NumericalDescription(space=(petal_length,))
petal_width_description = NumericalDescription(space=(petal_width,))
klass_description = CategoryDescription(space=(klass,))
[9]:
predicate_universe = PredicateUniverse(
    descriptions=(
        sepal_length_description,
        sepal_width_description,
        petal_length_description,
        petal_width_description,
        klass_description,
    )
)
len(predicate_universe)
[9]:
0

Creating context and Galois connection#

Create the formal context from items and predicates, then derive the associated Galois connection.

[10]:
from galactic.algebras.convex.descriptions.core import (
    Context,
    GaloisConnection,
)
[11]:
context = Context(item_universe, predicate_universe)
[12]:
connection = GaloisConnection(context)

Creating top concept#

Instantiate the top concept from the connection and inspect its intent and domain sizes.

[13]:
from galactic.algebras.convex.descriptions.core import (
    Concept,
)
[14]:
top = Concept(connection)
[str(attr) for attr in top.intent]
[14]:
['sepal_length ≥ 4.3',
 'sepal_length ≤ 7.9',
 'sepal_width ≥ 2.0',
 'sepal_width ≤ 4.4',
 'petal_length ≥ 1.0',
 'petal_length ≤ 6.9',
 'petal_width ≥ 0.1',
 'petal_width ≤ 2.5',
 "class ∈ {'Iris-setosa', 'Iris-versicolor', 'Iris-virginica'}"]
[15]:
len(context.domain), len(context.co_domain)
[15]:
(150, 9)

Creating lattice#

Initialise an extensible concept lattice from the top concept and render it as a Hasse diagram.

[16]:
from galactic.algebras.concept.core import ExtensibleLattice
[17]:
lattice = ExtensibleLattice([top])
[18]:
from galactic.algebras.concept.renderer import (
    ConceptRenderer,
    ConceptHasseDiagramDrawer,
)
[19]:
drawer = ConceptHasseDiagramDrawer(domain_renderer=ConceptRenderer(display_items=False))
drawer.draw(lattice)
[19]:
../../../../../_images/share_galactic_samples_iris_notebooks_notebook_24_0.svg

Creating quantile strategies#

Prepare quantile-based split strategies for each numerical feature to generate candidate concept refinements.

[20]:
from galactic.algebras.convex.strategies.numerical.quantile.core import (
    QuantileStrategy,
)
[21]:
strategy_sepal_length = QuantileStrategy(
    space=(sepal_length,),
    cutoff=None,
    quantile=None,
)
strategy_sepal_width = QuantileStrategy(
    space=(sepal_width,),
    cutoff=None,
    quantile=None
)
strategy_petal_length = QuantileStrategy(
    space=(petal_length,),
    cutoff=None,
    quantile=None
)
strategy_petal_width = QuantileStrategy(
    space=(petal_width,),
    cutoff=None,
    quantile=None
)

Creating composite strategy#

Combine the feature-level quantile strategies into a single composite strategy.

[22]:
from galactic.algebras.convex.strategies.core import CompositeStrategy
[23]:
mixed_strategy=CompositeStrategy(
    strategies=(
        strategy_sepal_length,
        strategy_sepal_width,
        strategy_petal_length,
        strategy_petal_width,
    )
)

Creating selective strategy#

Wrap the composite strategy with entropy-based selection to keep the most informative refinements.

[24]:
from galactic.algebras.convex.strategies.core import SelectiveStrategy
from galactic.algebras.convex.measures.entropy.core import Entropy
[25]:
entropy = Entropy(category=klass)
selective_strategy = SelectiveStrategy(
    strategies=(mixed_strategy,),
    measure=entropy,
    ratio=1,
)
[26]:
concepts = list(selective_strategy(top))
[27]:
lattice.extend(concepts)
[28]:
len(lattice.meet_irreducible), len(lattice.join_irreducible), len(context.co_domain)
[28]:
(2, 2, 373)
[29]:
drawer.draw(lattice)
[29]:
../../../../../_images/share_galactic_samples_iris_notebooks_notebook_37_0.svg

Applying the recursive strategy#

Apply recursion over the selected refinements to iteratively expand the concept lattice, limiting the support of recursion to 45.

[30]:
from galactic.algebras.convex.strategies.core import RecursiveStrategy
[31]:
recursive_strategy = RecursiveStrategy(
    strategies=(selective_strategy,),
    support=45,
)
[32]:
concepts = list(recursive_strategy(top))
[33]:
lattice.extend(concepts)
[34]:
len(lattice.meet_irreducible), len(lattice.join_irreducible), len(context.co_domain)
[34]:
(7, 6, 373)
[35]:
drawer.draw(lattice)
[35]:
../../../../../_images/share_galactic_samples_iris_notebooks_notebook_44_0.svg