feat: persist and load explained variance for scree plots

- compute_svd_for_window now computes explained variance ratio (s²/sum(s²))
  and appends it as a metadata row (entity_type='metadata',
  entity_id='explained_variance') to motion_rows
- load_scree_data reads this metadata row from svd_vectors instead of
  querying the non-existent sv_metadata column
- run_svd_for_window counts only entity_type='motion' rows in stored_motion
  so metadata rows don't inflate the count
- Added 5 TDD tests covering load, compute, store, and round-trip

All 227 tests pass.
This commit is contained in:
2026-05-01 10:34:31 +02:00
parent 121c32ae8a
commit 6e36fa2604
3 changed files with 267 additions and 8 deletions
+21 -7
View File
@@ -346,14 +346,28 @@ def load_party_mp_vectors(db_path: str) -> Dict[str, List[np.ndarray]]:
def load_scree_data(db_path: str) -> List[float]:
"""Load scree plot data (explained variance) for current_parliament.
"""Load scree plot data (explained variance) for current_parliament."""
try:
con = duckdb.connect(database=db_path, read_only=True)
row = con.execute(
"""
SELECT vector FROM svd_vectors
WHERE window_id = 'current_parliament'
AND entity_type = 'metadata'
AND entity_id = 'explained_variance'
LIMIT 1
"""
).fetchone()
con.close()
TODO: Scree data requires SVD metadata (singular values / explained
variance ratios) to be stored in the database. Currently only
transformed vectors are stored in svd_vectors.vector, not the
decomposition metadata needed for a scree plot.
"""
return []
if row and row[0]:
import json
return json.loads(row[0])
return []
except Exception:
logger.exception("Failed to load scree data")
return []
def load_motions_df(db_path: str) -> pd.DataFrame: