Source code for pretab.transformers.embeddings.language_transformer
import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin
from ...core.exceptions import OptionalDependencyError, PretabConfigError
[docs]
class LanguageEmbeddingTransformer(TransformerMixin, BaseEstimator):
"""Encode categorical text features into embeddings using a pre-trained language model.
Each text value is mapped to a dense embedding vector produced by a
SentenceTransformer model, allowing free-text categorical columns to be used
by downstream numerical models.
Parameters
----------
model_name : str, default="paraphrase-MiniLM-L3-v2"
Name of the SentenceTransformer model to load when ``model`` is None.
model : object, optional
A preloaded SentenceTransformer model instance. When provided,
``model_name`` is ignored.
Attributes
----------
model_ : object
The SentenceTransformer model used to compute embeddings, resolved during
``fit`` from ``model`` or by loading ``model_name``.
n_features_in_ : int
Number of input features seen during ``fit``.
Notes
-----
Requires the optional ``sentence-transformers`` dependency. Install it with
``pip install sentence-transformers`` or pass a preloaded ``model``.
Examples
--------
>>> from pretab.transformers import LanguageEmbeddingTransformer
>>> transformer = LanguageEmbeddingTransformer() # doctest: +SKIP
>>> embeddings = transformer.fit_transform([["red"], ["blue"], ["green"]]) # doctest: +SKIP
>>> embeddings.shape[0] # doctest: +SKIP
3
"""
[docs]
def __init__(self, model_name="paraphrase-MiniLM-L3-v2", model=None):
"""Store parameters only; the embedding model is loaded lazily in ``fit``."""
self.model_name = model_name
self.model = model # Allow user to pass a preloaded model
def _resolve_model(self):
"""Return the preloaded ``model`` or load one from ``model_name``."""
if self.model is not None:
return self.model
try:
from sentence_transformers import SentenceTransformer
except ImportError as e:
raise OptionalDependencyError(
"sentence-transformers is not installed. Install it via `pip install sentence-transformers` or provide a preloaded model."
) from e
return SentenceTransformer(self.model_name)
[docs]
def fit(self, X, y=None):
"""Load the embedding model and record the number of input features.
Parameters
----------
X : array-like
Input categorical text features.
y : Ignored
Not used, present for API consistency by convention.
Returns
-------
self : object
Fitted transformer.
"""
self.n_features_in_ = X.shape[1] if len(X.shape) > 1 else 1
self.model_ = self._resolve_model()
return self
[docs]
def transform(self, X):
"""Transform text features into numerical embeddings.
Each column is encoded independently and the resulting embeddings are
concatenated horizontally, so the output always has one row per input
sample regardless of the number of text columns.
Parameters
----------
X : array-like
A 1D or 2D array-like of categorical text features.
Returns
-------
embeddings : ndarray of shape (n_samples, n_features * embedding_dim)
The concatenated embeddings for each text input.
"""
if getattr(self, "model_", None) is None:
raise PretabConfigError(
"Model is not initialized. Call `fit` before `transform`."
)
# Normalise to a 2D array of strings so each column is encoded on its own
# and the row count is preserved (a flat encode would return
# n_samples * n_features rows).
arr = np.asarray(X)
if arr.ndim == 1:
arr = arr.reshape(-1, 1)
arr = arr.astype(str)
column_embeddings = [
self.model_.encode(arr[:, i].tolist(), convert_to_numpy=True)
for i in range(arr.shape[1])
]
return np.hstack(column_embeddings)