---
title: "SVD Labels Should Reflect Voting Patterns, Not Semantic Content"
date: "2026-04-04"
category: docs/solutions/best-practices
module: stemwijzer
problem_type: best_practice
component: brief_system
severity: medium
applies_when:
  - Labeling SVD (Singular Value Decomposition) components in voting analysis
  - Interpreting PCA/SVD dimensions in political party voting data
  - Creating axis labels for voting compass or similar applications
tags:
  - svd
  - voting-analysis
  - axis-labels
  - dimensionality-reduction
  - party-voting-patterns
---

# SVD Labels Should Reflect Voting Patterns, Not Semantic Content

## Context

When labeling SVD components in the Stemwijzer explorer (`explorer.py`), initial labels were based on **semantic analysis** of motion titles — what topics motions appeared to discuss. However, SVD captures **voting patterns**, not semantic content.

This mismatch led to:
- Labels that didn't match how parties actually voted
- Right-wing parties appearing on the LEFT side of axes (violating the right-wing parties → right side constraint)
- Confusion about what each component actually represents

## Guidance

### The Core Principle

**SVD components represent voting unity patterns, not topic clusters.**

When a motion appears on a component with a positive loading, it means parties that vote positively on that motion tend to vote similarly. The component captures this behavioral pattern, not the topic's semantic meaning.

### Example: Component 1

| Approach | Label | Why It's Wrong |
|----------|-------|----------------|
| Semantic | "Sociale zekerheid vs economische liberalisering" | Assumes defense + social care = welfare state |
| Voting | "Rechts kabinetsbeleid vs links oppositiebeleid" | Matches actual coalition vs opposition voting |

**Why Component 1 captures coalition-opposition:**
- 9 coalition + center parties vote one way
- 6 opposition parties vote the other way
- Motion topics can include defense (right votes for) AND social care (left votes for) because they're on opposite sides of the coalition-opposition divide

### How to Label SVD Components

1. **Analyze actual voting patterns first**
   - Query which parties vote positively vs negatively on each component
   - Look for coalition/opposition splits, cross-block alliances, or isolated parties

2. **Verify right-wing parties on RIGHT side**
   - Check PVV, FVD, JA21, SGP positions
   - If they vote negatively while left parties vote positively, flip the axis

3. **Don't assume semantics match voting**
   - A "defense" component may include social care motions if right-wing parties vote the same way on both
   - Cross-block alliances (e.g., PVV with SP on welfare) create components that don't fit left-right semantics

4. **Test with sample motions**
   - Top positive-loading motions should align with positive-voting parties' priorities
   - Top negative-loading motions should align with negative-voting parties' priorities

## Why This Matters

Without understanding that SVD captures voting patterns:
- Labels will be misleading to users
- Right-wing parties may appear on the wrong side of axes
- Components may be mislabeled as "left" when they're actually "opposition"
- Users get incorrect information about party positions

## When to Apply

Apply this guidance when:
- Creating or updating SVD/PCA component labels
- Interpreting dimensionality reduction results in voting analysis
- Building voting compasses or similar political guidance tools
- Analyzing roll call votes or legislative voting data

## Examples

### Wrong Approach (Semantic)

```python
# ❌ BAD: Based on motion topics, not voting patterns
SVD_THEMES = {
    1: {
        "label": "Sociale zekerheid vs economische liberalisering",
        # Reality: 9 coalition parties vote same way, 6 opposition vote opposite
    }
}
```

### Correct Approach (Voting Patterns)

```python
# ✅ GOOD: Based on actual voting behavior
SVD_THEMES = {
    1: {
        "label": "Rechts kabinetsbeleid vs links oppositiebeleid",
        "explanation": (
            "Deze as scheidt het kabinetsbeleid van de oppositie. "
            "9 coalitiepartijen stemmen aan de positieve kant, "
            "6 oppositiepartijen aan de negatieve kant."
        ),
    }
}
```

### Verification Approach

To verify SVD component labels, check which parties have positive vs negative loadings on each component:

```python
# From explorer.py - check party loadings for each component
for comp_num in range(1, 11):
    component_parties = svd_scores[svd_scores['component'] == comp_num]
    positive_parties = component_parties[component_parties['loading'] > 0]['party'].tolist()
    negative_parties = component_parties[component_parties['loading'] < 0]['party'].tolist()
    
    print(f"Component {comp_num}:")
    print(f"  Positive ({len(positive_parties)}): {positive_parties}")
    print(f"  Negative ({len(negative_parties)}): {negative_parties}")
```

Use this to verify:
- Right-wing parties (PVV, FVD, JA21, SGP) appear on the correct side
- The label matches the voting pattern, not just the topic

## Related

- [SVD Label Unification Plan](docs/superpowers/plans/2026-04-02-svd-label-unification.md)
- [SVD Label Unification Design](docs/superpowers/specs/2026-04-02-svd-label-unification-design.md)
- Commits: `33edb33`, `e77f0ec`, `bfe37c6`, `f7fc908`, `92c3c0e`
