artlib.supervised.SimpleARTMAP ============================== .. py:module:: artlib.supervised.SimpleARTMAP .. autoapi-nested-parse:: Simple ARTMAP :cite:`gotarredona1998adaptive`. Classes ------- .. autoapisummary:: artlib.supervised.SimpleARTMAP.SimpleARTMAP Module Contents --------------- .. py:class:: SimpleARTMAP(module_a: artlib.common.BaseART.BaseART) Bases: :py:obj:`artlib.common.BaseARTMAP.BaseARTMAP` SimpleARTMAP for Classification. This module implements SimpleARTMAP as first published in: :cite:`gotarredona1998adaptive`. .. # Serrano-Gotarredona, T., Linares-Barranco, B., & Andreou, A. G. (1998). .. # Adaptive Resonance Theory Microchips: Circuit Design Techniques. .. # Norwell, MA, USA: Kluwer Academic Publishers. SimpleARTMAP is a special case of :class:`~artlib.supervised.ARTMAP.ARTMAP` specifically for classification. It allows the clustering of data samples while enforcing a many-to-one mapping from sample clusters to labels. It accepts an instantiated :class:`~artlib.common.BaseART.BaseART` module and dynamically adapts the vigilance function to prevent resonance when the many-to-one mapping is violated. This enables SimpleARTMAP to identify discrete clusters belonging to each category label. .. py:attribute:: module_a .. py:method:: match_reset_func(i: numpy.ndarray, w: numpy.ndarray, cluster_a, params: dict, extra: dict, cache: Optional[dict] = None) -> bool Permits external factors to influence cluster creation. :param i: Data sample. :type i: np.ndarray :param w: Cluster weight / info. :type w: np.ndarray :param cluster_a: A-side cluster label. :type cluster_a: int :param params: Parameters for the algorithm. :type params: dict :param extra: Additional parameters, including "cluster_b". :type extra: dict :param cache: Values cached from previous calculations. :type cache: dict, optional :returns: True if the match is permitted, False otherwise. :rtype: bool .. py:method:: get_params(deep: bool = True) -> dict Get parameters of the model. :param deep: If True, will return the parameters for this class and contained subobjects that are estimators. :type deep: bool, default=True :returns: Parameter names mapped to their values. :rtype: dict .. py:method:: validate_data(X: numpy.ndarray, y: numpy.ndarray) -> tuple[numpy.ndarray, numpy.ndarray] Validate data prior to clustering. :param X: Data set A. :type X: np.ndarray :param y: Data set B. :type y: np.ndarray :returns: The validated datasets X and y. :rtype: tuple[np.ndarray, np.ndarray] .. py:method:: prepare_data(X: numpy.ndarray, y: Optional[numpy.ndarray] = None) -> Union[numpy.ndarray, Tuple[numpy.ndarray, numpy.ndarray]] Prepare data for clustering. :param X: Data set. :type X: np.ndarray :param y: Data set B. Not used in SimpleARTMAP :type y: Optional[np.ndarray] :returns: Prepared data. :rtype: np.ndarray .. py:method:: restore_data(X: numpy.ndarray, y: Optional[numpy.ndarray] = None) -> Union[numpy.ndarray, Tuple[numpy.ndarray, numpy.ndarray]] Restore data to state prior to preparation. :param X: Data set. :type X: np.ndarray :returns: Restored data. :rtype: np.ndarray .. py:method:: step_fit(x: numpy.ndarray, c_b: int, match_tracking: Literal['MT+', 'MT-', 'MT0', 'MT1', 'MT~'] = 'MT+', epsilon: float = 1e-10) -> int Fit the model to a single sample. :param x: Data sample for side A. :type x: np.ndarray :param c_b: Side B label. :type c_b: int :param match_tracking: Method to reset the match. :type match_tracking: Literal, default="MT+" :param epsilon: Small value to adjust the vigilance. :type epsilon: float, default=1e-10 :returns: Side A cluster label. :rtype: int .. py:method:: fit(X: numpy.ndarray, y: numpy.ndarray, max_iter=1, match_tracking: Literal['MT+', 'MT-', 'MT0', 'MT1', 'MT~'] = 'MT+', epsilon: float = 1e-10, verbose: bool = False, leave_progress_bar: bool = True) Fit the model to the data. :param X: Data set A. :type X: np.ndarray :param y: Data set B. :type y: np.ndarray :param max_iter: Number of iterations to fit the model on the same data set. :type max_iter: int, default=1 :param match_tracking: Method to reset the match. :type match_tracking: Literal, default="MT+" :param epsilon: Small value to adjust the vigilance. :type epsilon: float, default=1e-10 :param verbose: If True, displays a progress bar during training. :type verbose: bool, default=False :param leave_progress_bar: If True, leaves thge progress of the fitting process. Only used when verbose=True :type leave_progress_bar: bool, default=True :returns: **self** -- The fitted model. :rtype: SimpleARTMAP .. py:method:: fit_predict(X: numpy.ndarray, y: numpy.ndarray, max_iter=1, match_tracking: Literal['MT+', 'MT-', 'MT0', 'MT1', 'MT~'] = 'MT+', epsilon: float = 1e-10, verbose: bool = False, leave_progress_bar: bool = True) Fit the model to the data and return the labels. Need to define this or ClusterMixin could cause issues. :param X: Data set A. :type X: np.ndarray :param y: Data set B. :type y: np.ndarray :param max_iter: Number of iterations to fit the model on the same data set. :type max_iter: int, default=1 :param match_tracking: Method to reset the match. :type match_tracking: Literal, default="MT+" :param epsilon: Small value to adjust the vigilance. :type epsilon: float, default=1e-10 :param verbose: If True, displays a progress bar during training. :type verbose: bool, default=False :param leave_progress_bar: If True, leaves thge progress of the fitting process. Only used when verbose=True :type leave_progress_bar: bool, default=True :returns: The labels (same as y). :rtype: np.ndarray .. py:method:: fit_gif(X: numpy.ndarray, y: numpy.ndarray, match_tracking: Literal['MT+', 'MT-', 'MT0', 'MT1', 'MT~'] = 'MT+', epsilon: float = 1e-10, verbose: bool = False, leave_progress_bar: bool = True, ax: Optional[matplotlib.axes.Axes] = None, filename: Optional[str] = None, fps: int = 5, final_hold_secs: float = 0.0, colors: Optional[artlib.common.utils.IndexableOrKeyable] = None, n_class_estimate: Optional[int] = None, max_iter: int = 1, **kwargs) Fit the model while recording the learning process as an animated GIF. The routine iterates over the training data, calling :py:meth:`step_fit` for each sample, and captures intermediate plots by repeatedly invoking :py:meth:`visualize`. All frames are written to a GIF file (via ``matplotlib.animation.PillowWriter``), allowing an intuitive, frame‑by‑frame view of how clusters form and adjust over time. :param X: Independent‑channel samples (side A), shape ``(n_samples, n_features)``. :type X: np.ndarray :param y: Target labels (side B), shape ``(n_samples,)``. :type y: np.ndarray :param match_tracking: Strategy used by the ART module to reset its match criterion. :type match_tracking: {"MT+", "MT-", "MT0", "MT1", "MT~"}, default="MT+" :param epsilon: Small positive constant added to the vigilance when ``match_tracking`` triggers a reset. :type epsilon: float, default=1e‑10 :param verbose: If ``True``, displays a tqdm progress bar for each epoch. :type verbose: bool, default=False :param leave_progress_bar: If ``True``, leaves the progress bar visible after completion (only relevant when ``verbose`` is ``True``). :type leave_progress_bar: bool, default=True :param ax: Existing axes on which to draw frames. If ``None``, a new figure and axes are created. :type ax: matplotlib.axes.Axes, optional :param filename: Output path for the GIF. Defaults to ``"fit_gif_supervised_.gif"`` if ``None``. :type filename: str, optional :param fps: Frames per second in the resulting GIF. :type fps: int, default=5 :param final_hold_secs: Extra seconds to hold the final frame (duplicates the last plot ``ceil(final_hold_secs * fps)`` times). :type final_hold_secs: float, default=0.0 :param colors: Sequence of colors to use for each class when plotting. If ``None``, a rainbow colormap is generated. :type colors: array‑like, optional :param n_class_estimate: Expected number of distinct classes. Only used when ``colors`` is ``None`` to size the autogenerated colormap. :type n_class_estimate: int, optional :param max_iter: Number of complete passes over ``(X, y)``. :type max_iter: int, default=1 :param \*\*kwargs: Additional keyword arguments forwarded to :py:meth:`visualize` (e.g., ``marker_size``, ``linewidth``). :returns: **self** -- The fitted estimator (identical object, returned for chaining). :rtype: SimpleARTMAP .. rubric:: Notes * Generates a GIF file as a **side‑effect**. The estimator itself is updated exactly as in :py:meth:`fit`; only plotting calls and file I/O are added. * For reproducible colors across different runs, supply an explicit ``colors`` array rather than relying on the rainbow colormap. .. py:method:: partial_fit(X: numpy.ndarray, y: numpy.ndarray, match_tracking: Literal['MT+', 'MT-', 'MT0', 'MT1', 'MT~'] = 'MT+', epsilon: float = 1e-10) Partial fit the model to the data. :param X: Data set A. :type X: np.ndarray :param y: Data set B. :type y: np.ndarray :param match_tracking: Method to reset the match. :type match_tracking: Literal, default="MT+" :param epsilon: Small value to adjust the vigilance. :type epsilon: float, default=1e-10 :returns: **self** -- The partially fitted model. :rtype: SimpleARTMAP .. py:property:: labels_a :type: numpy.ndarray Get labels from side A (module A). :returns: Labels from module A. :rtype: np.ndarray .. py:property:: labels_b :type: numpy.ndarray Get labels from side B. :returns: Labels from side B. :rtype: np.ndarray .. py:property:: labels_ab :type: Dict[str, numpy.ndarray] Get labels from both A-side and B-side. :returns: A dictionary with keys "A" and "B" containing labels from sides A and B, respectively. :rtype: dict .. py:property:: n_clusters :type: int Get the number of clusters in side A. :returns: Number of clusters. :rtype: int .. py:property:: n_clusters_a :type: int Get the number of clusters in side A. :returns: Number of clusters in side A. :rtype: int .. py:property:: n_clusters_b :type: int Get the number of clusters in side B. :returns: Number of clusters in side B. :rtype: int .. py:method:: step_pred(x: numpy.ndarray) -> tuple[int, int] Predict the label for a single sample. :param x: Data sample for side A. :type x: np.ndarray :returns: Side A cluster label, side B cluster label. :rtype: tuple[int, int] .. py:method:: predict(X: numpy.ndarray, clip: bool = False) -> numpy.ndarray Predict labels for the data. :param X: Data set A. :type X: np.ndarray :param clip: clip the input values to be between the previously seen data limits :type clip: bool :returns: B labels for the data. :rtype: np.ndarray .. py:method:: predict_ab(X: numpy.ndarray, clip: bool = False) -> tuple[numpy.ndarray, numpy.ndarray] Predict labels for the data, both A-side and B-side. :param X: Data set A. :type X: np.ndarray :param clip: clip the input values to be between the previously seen data limits :type clip: bool :returns: A labels for the data, B labels for the data. :rtype: tuple[np.ndarray, np.ndarray] .. py:method:: plot_cluster_bounds(ax: matplotlib.axes.Axes, colors: artlib.common.utils.IndexableOrKeyable, linewidth: int = 1) Visualize the cluster boundaries. :param ax: Figure axes. :type ax: Axes :param colors: Colors to use for each cluster. :type colors: IndexableOrKeyable :param linewidth: Width of boundary lines. :type linewidth: int, default=1 .. py:method:: visualize(X: numpy.ndarray, y: numpy.ndarray, ax: Optional[matplotlib.axes.Axes] = None, marker_size: int = 10, linewidth: int = 1, colors: Optional[artlib.common.utils.IndexableOrKeyable] = None) Visualize the clustering of the data. :param X: Data set. :type X: np.ndarray :param y: Sample labels. :type y: np.ndarray :param ax: Figure axes. :type ax: Optional[Axes], default=None :param marker_size: Size used for data points. :type marker_size: int, default=10 :param linewidth: Width of boundary lines. :type linewidth: int, default=1 :param colors: Colors to use for each cluster. :type colors: Optional[Iterable], default=None