5.3 KiB
| title | date | category | module | problem_type | component | severity | applies_when | tags |
|---|---|---|---|---|---|---|---|---|
| SVD Labels Should Reflect Voting Patterns, Not Semantic Content | 2026-04-04 | docs/solutions/best-practices | stemwijzer | best_practice | brief_system | medium | [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] | [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
-
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
-
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
-
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
-
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)
# ❌ 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)
# ✅ 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:
# 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
- SVD Label Unification Design
- Commits:
33edb33,e77f0ec,bfe37c6,f7fc908,92c3c0e