Source code for mantispy.metrics._evaluate

"""Compare representations on one table."""

from __future__ import annotations

from collections.abc import Sequence
from typing import TYPE_CHECKING

import pandas as pd

from mantispy.metrics._common import tidy
from mantispy.metrics._lisi import lisi
from mantispy.metrics._silhouette import silhouette_batch, silhouette_label
from mantispy.metrics._variance import pc_regression

if TYPE_CHECKING:
    from anndata import AnnData

#: Which direction is better, per metric. Batch mixing and biological separation trade off
#: against each other, so read them together.
BETTER = {
    "silhouette_label": "higher",
    "silhouette_batch": "higher",
    "ilisi": "higher",
    "clisi": "lower",
    "pc_regression": "lower",
    "mean_average_precision": "higher",
}


[docs] def evaluate_correction( adata: AnnData, reps: Sequence[str] = ("X_pca",), label_key: str = "Metadata_Perturbation", batch_key: str = "Metadata_Batch", map_key: str | None = None, ) -> pd.DataFrame: """Run every metric for every representation and stack the results. Args: adata: Object holding the representations in ``obsm``. reps: Representations to compare, e.g. ``("X_pca", "X_pca_harmony")``. label_key: ``obs`` column with the biological grouping. batch_key: ``obs`` column with the nuisance grouping. map_key: Name of a table written by :func:`~mantispy.tl.map`, to add its mean mAP as one more row per representation. Returns: A tidy frame with ``metric``, ``representation``, ``key``, ``value`` and ``better``, the last saying which direction is an improvement for that metric. """ frames = [] for rep in reps: frames += [ silhouette_label(adata, label_key=label_key, use_rep=rep), silhouette_batch(adata, label_key=label_key, batch_key=batch_key, use_rep=rep), # kind is explicit because a batch_key such as "Metadata_Site" would otherwise be # named clisi and share a metric name with the label row. lisi(adata, key=batch_key, use_rep=rep, kind="batch"), lisi(adata, key=label_key, use_rep=rep, kind="label"), pc_regression(adata, key=batch_key, use_rep=rep), ] if map_key is not None: table = adata.uns.get("mantispy", {}).get(map_key) if table is None: raise KeyError(f"uns['mantispy'] has no {map_key!r}; run mt.tl.map first") frames.append(tidy("mean_average_precision", rep, label_key, float(table["mean_average_precision"].mean()))) result = pd.concat(frames, ignore_index=True) result["better"] = result["metric"].map(BETTER) return result