The geometric module analyzes embedding geometry to detect shortcuts.
::: shortcut_detect.geometric.GeometricShortcutAnalyzer options: show_root_heading: true show_source: true
GeometricShortcutAnalyzer(
n_components: int = 5,
normalize: bool = True,
random_state: int = None
)| Parameter | Type | Default | Description |
|---|---|---|---|
n_components |
int | 5 | PCA components per group |
normalize |
bool | True | Normalize embeddings |
random_state |
int | None | Random seed |
def fit(
embeddings: np.ndarray,
group_labels: np.ndarray
) -> GeometricShortcutAnalyzerAnalyze geometric structure of embeddings.
Parameters:
| Parameter | Type | Description |
|---|---|---|
embeddings |
ndarray | Shape (n_samples, n_features) |
group_labels |
ndarray | Shape (n_samples,) |
Returns: self
def transform(embeddings: np.ndarray) -> np.ndarrayProject embeddings onto bias direction.
def debias(embeddings: np.ndarray) -> np.ndarrayRemove bias direction from embeddings.
| Attribute | Type | Description |
|---|---|---|
bias_direction_ |
ndarray | Unit vector between group centroids |
bias_effect_size_ |
float | Cohen's d along bias direction |
subspace_overlap_ |
float | Principal angle overlap (0-1) |
group_centroids_ |
dict | Centroid per group |
group_pca_ |
dict | PCA model per group |
projections_ |
dict | Projections per group |
summary_ |
str | Human-readable summary |
from shortcut_detect import GeometricShortcutAnalyzer
analyzer = GeometricShortcutAnalyzer(n_components=5)
analyzer.fit(embeddings, group_labels)
print(analyzer.summary_)
print(f"Effect size: {analyzer.bias_effect_size_:.2f}")
print(f"Subspace overlap: {analyzer.subspace_overlap_:.2f}")analyzer.fit(embeddings, group_labels)
# Remove bias direction
embeddings_debiased = analyzer.debias(embeddings)
# Verify debiasing
analyzer_after = GeometricShortcutAnalyzer()
analyzer_after.fit(embeddings_debiased, group_labels)
print(f"Effect size after: {analyzer_after.bias_effect_size_:.2f}")import matplotlib.pyplot as plt
# Project onto bias direction
projections = analyzer.transform(embeddings)
fig, ax = plt.subplots(figsize=(10, 4))
for group in np.unique(group_labels):
mask = group_labels == group
ax.hist(projections[mask], bins=50, alpha=0.5, label=f'Group {group}')
ax.legend()
ax.set_xlabel('Bias Direction Projection')
plt.savefig('bias_projections.png')