Spaces:
Runtime error
Runtime error
| import os | |
| import numpy as np | |
| import pandas as pd | |
| from scipy.sparse import load_npz | |
| from sklearn.metrics.pairwise import cosine_similarity | |
| SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) | |
| PROJECT_ROOT = os.path.dirname(os.path.dirname(SCRIPT_DIR)) | |
| SEG = os.path.join(PROJECT_ROOT, "data", "segmented") | |
| EMB = os.path.join(PROJECT_ROOT, "data", "embeddings") | |
| df = pd.read_csv(os.path.join(SEG, "clauses_features.csv")) | |
| embeddings = np.load(os.path.join(EMB, "sbert_embeddings.npy")) | |
| tfidf = load_npz(os.path.join(EMB, "tfidf_matrix.npz")) | |
| labels = np.load(os.path.join(EMB, "labels_encoded.npy")) | |
| lines = [] | |
| def log(msg=""): | |
| print(msg) | |
| lines.append(msg) | |
| log("=" * 60) | |
| log("DATASET VALIDATION REPORT") | |
| log("=" * 60) | |
| # ββ Basic stats βββββββββββββββββββββββββββββββββββββββββββ | |
| log("\n[1] CORPUS STATS") | |
| log(f" Total clauses : {len(df)}") | |
| log(f" Unique source docs : {df['source_doc'].nunique()}") | |
| log(f" Domains : {dict(df['domain'].value_counts())}") | |
| log(f" Avg word count : {df['word_count'].mean():.1f}") | |
| log(f" Avg token count : {df['token_count'].mean():.1f}") | |
| # ββ Label distribution ββββββββββββββββββββββββββββββββββββ | |
| log("\n[2] LABEL DISTRIBUTION") | |
| counts = df['risk_label'].value_counts() | |
| for label, cnt in counts.items(): | |
| pct = cnt / len(df) * 100 | |
| bar = "β" * (cnt // 40) | |
| log(f" {label:<12} {cnt:>5} ({pct:.1f}%) {bar}") | |
| ratio = counts.max() / counts.min() | |
| log(f"\n Imbalance ratio : {ratio:.2f}x {'β good' if ratio < 1.5 else 'β check'}") | |
| # ββ Feature stats βββββββββββββββββββββββββββββββββββββββββ | |
| log("\n[3] LINGUISTIC FEATURE STATS") | |
| feat_cols = ["modal_score", "consequence_score", "conditional_score", | |
| "has_negation", "obligation_count", "penalty_flag"] | |
| for col in feat_cols: | |
| if col in df.columns: | |
| log(f" {col:<25} mean={df[col].mean():.3f} std={df[col].std():.3f}") | |
| # ββ 4. Embedding sanity ββββββββββββββββββββββββββββββββββββββ | |
| log("\n[4] EMBEDDING SANITY CHECKS") | |
| log(f" SBERT shape : {embeddings.shape}") | |
| log(f" TF-IDF shape : {tfidf.shape}") | |
| log(f" SBERT mean norm : {np.linalg.norm(embeddings, axis=1).mean():.3f}") | |
| log(f" Any NaN in SBERT : {np.isnan(embeddings).any()}") | |
| log(f" Labels shape : {labels.shape}") | |
| log(f" Labels aligned : {len(labels) == len(df)}") | |
| # ββ Inter-class separability ββββββββββββββββββββββββββββββ | |
| log("\n[5] INTER-CLASS SEPARABILITY (SBERT cosine similarity)") | |
| label_list = ["Critical", "High", "Medium", "Low"] | |
| log(" Intra-class (higher = more cohesive):") | |
| for label in label_list: | |
| idx = df[df['risk_label'] == label].index.tolist() | |
| if len(idx) < 2: | |
| continue | |
| sample = embeddings[idx[:100]] | |
| sim = cosine_similarity(sample) | |
| np.fill_diagonal(sim, 0) | |
| log(f" {label:<12} {sim.mean():.3f}") | |
| log("\n Cross-class (lower = better separation):") | |
| for i, l1 in enumerate(label_list): | |
| for l2 in label_list[i+1:]: | |
| idx1 = df[df['risk_label'] == l1].index[:50] | |
| idx2 = df[df['risk_label'] == l2].index[:50] | |
| if len(idx1) == 0 or len(idx2) == 0: | |
| continue | |
| sim = cosine_similarity(embeddings[idx1], embeddings[idx2]) | |
| log(f" {l1} vs {l2:<12} {sim.mean():.3f}") | |
| # ββ Domain x label coverage βββββββββββββββββββββββββββββββ | |
| log("\n[6] DOMAIN x LABEL COVERAGE") | |
| pivot = df.groupby(['domain', 'risk_label']).size().unstack(fill_value=0) | |
| for col in ["Critical", "High", "Medium", "Low"]: | |
| if col not in pivot.columns: | |
| pivot[col] = 0 | |
| log(pivot[["Critical", "High", "Medium", "Low"]].to_string()) | |
| # ββ Readiness checklist βββββββββββββββββββββββββββββββββββ | |
| log("\n[7] READINESS CHECKLIST") | |
| checks = { | |
| "4 risk labels present" : df['risk_label'].nunique() == 4, | |
| "Min 500 per class" : counts.min() >= 500, | |
| "SBERT no NaN" : not np.isnan(embeddings).any(), | |
| "Embeddings aligned" : len(labels) == len(df), | |
| "TF-IDF features > 1000" : tfidf.shape[1] > 1000, | |
| "Linguistic features exist" : all(c in df.columns for c in feat_cols), | |
| "Imbalance ratio < 2x" : ratio < 2.0, | |
| } | |
| all_pass = True | |
| for check, result in checks.items(): | |
| status = "β" if result else "β" | |
| log(f" {status} {check}") | |
| if not result: | |
| all_pass = False | |
| log(f"\n {'β ALL CHECKS PASSED' if all_pass else 'β FIX THE ISSUES ABOVE'}") | |
| # Save validation report | |
| report_path = os.path.join(SEG, "validation_report.txt") | |
| with open(report_path, "w", encoding="utf-8") as f: | |
| f.write("\n".join(lines)) | |
| print(f"\nβ Validation report saved β {report_path}") | |
| # ============================================================ | |
| # FINAL EXPORT | |
| # ============================================================ | |
| master_cols = [ | |
| "clause_id", "source_doc", "domain", | |
| "raw_text", "clean_text", | |
| "word_count", "token_count", | |
| "pattern_label", "risk_label", "risk_score", | |
| "modal_score", "consequence_score", "conditional_score", | |
| "has_negation", "obligation_count", "penalty_flag" | |
| ] | |
| master_cols = [c for c in master_cols if c in df.columns] | |
| master = df[master_cols].copy() | |
| master_path = os.path.join(SEG, "master_dataset.csv") | |
| master.to_csv(master_path, index=False) | |
| print(f"\nβ master_dataset.csv β {master_path}") | |
| print(f" Shape : {master.shape}") | |
| print(f" Columns : {list(master.columns)}") | |
| print(f"\n data/segmented/") | |
| print(f" master_dataset.csv β {master.shape[0]} clauses x {master.shape[1]} columns") | |
| print(f" clauses_balanced.csv β balanced training set (4000 clauses)") | |
| print(f" clauses_labeled.csv β full labeled set") | |
| print(f" validation_report.txt β quality report") | |
| print(f"\n data/embeddings/") | |
| print(f" sbert_embeddings.npy β {embeddings.shape} (dense semantic)") | |
| print(f" tfidf_matrix.npz β {tfidf.shape} (sparse lexical)") | |
| print(f" tfidf_vectorizer.pkl β fitted vectorizer for inference") | |
| print(f" labels_encoded.npy β integer labels {labels.shape}") | |
| print(f" label_encoder.pkl β class mapping") | |
| print(f" embedding_index.csv β clause_id alignment") | |
| print(f"\n Risk label mapping:") | |
| print(f" Critical β termination, criminal, damages") | |
| print(f" High β suspension, breach, prohibited") | |
| print(f" Medium β warning, obligation, compliance") | |
| print(f" Low β definitions, advisory, informational") | |