expense-tracker-backend / ml /tests /test_split.py
Yoge-2004's picture
Deploy production backend + ML: Java 27, PDF reports, Apache 2.0
006b72b
Raw History Blame Contribute Delete
4.62 kB
import pandas as pd
from expense_ml.data.split import remove_conflicting_text_groups, split_dataset
def test_split_is_deterministic_and_has_no_exact_text_leakage():
rows = []
for i in range(50):
rows.append({"text": f"merchant {i}", "label": "food", "source": "global", "country": "USA"})
rows.append({"text": f"merchant {i + 50}", "label": "transportation", "source": "global", "country": "Canada"})
rows.extend(
[
{"text": "repeated merchant", "label": "food", "source": "global", "country": "USA"},
{"text": "repeated merchant", "label": "food", "source": "finee-india", "country": "India"},
{"text": "repeated merchant", "label": "food", "source": "synthetic-indian-transactions", "country": "India"},
]
)
frame = pd.DataFrame(rows)
a = split_dataset(frame, seed=7, test_size=.2, validation_size=.1)
b = split_dataset(frame, seed=7, test_size=.2, validation_size=.1)
assert a.train["text"].tolist() == b.train["text"].tolist()
for left, right in (
(a.train, a.test),
(a.train, a.validation),
(a.train, a.india_holdout),
(a.validation, a.test),
(a.validation, a.india_holdout),
(a.test, a.india_holdout),
):
assert set(left["text"]) & set(right["text"]) == set()
combined_partition_texts = set().union(*(set(part["text"]) for part in (a.train, a.validation, a.test, a.india_holdout)))
assert "repeated merchant" in combined_partition_texts
assert "repeated merchant" not in set(a.india_holdout["text"])
def test_cross_country_duplicate_is_excluded_from_india_holdout():
frame = pd.DataFrame(
[
{"text": "same narration", "label": "food", "source": "global", "country": "USA"},
{"text": "same narration", "label": "food", "source": "global", "country": "India"},
]
+ [
{"text": f"india {i}", "label": "food", "source": "global", "country": "India"}
for i in range(100)
]
+ [
{"text": f"usa {i}", "label": "transportation", "source": "global", "country": "USA"}
for i in range(100)
]
)
result = split_dataset(frame, seed=17, test_size=.2, validation_size=.1)
assert "same narration" not in set(result.india_holdout["text"])
def test_split_uses_country_metadata_for_india_holdout():
frame = pd.DataFrame(
[
{"text": f"india {i}", "label": "food", "source": "global", "country": "India"}
for i in range(100)
]
+ [
{"text": f"usa {i}", "label": "transportation", "source": "global", "country": "USA"}
for i in range(100)
]
)
result = split_dataset(frame, seed=11, test_size=.2, validation_size=.1)
assert len(result.india_holdout) > 0
assert set(result.india_holdout["country"]) == {"India"}
def test_conflicting_text_groups_are_removed_before_splitting():
frame = pd.DataFrame(
[
{"text": "ambiguous narration", "label": "food_dining", "source": "global", "country": "USA"},
{"text": "ambiguous narration", "label": "shopping_retail", "source": "finee", "country": "India"},
{"text": "clear food", "label": "food_dining", "source": "global", "country": "USA"},
{"text": "clear transport", "label": "transportation", "source": "global", "country": "USA"},
]
)
cleaned, summary = remove_conflicting_text_groups(frame)
assert "ambiguous narration" not in set(cleaned["text"])
assert set(cleaned["text"]) == {"clear food", "clear transport"}
assert summary["conflicting_text_groups"] == 1
assert summary["rows_removed"] == 2
def test_split_removes_conflicting_groups_before_partitioning():
rows = [
{"text": "ambiguous narration", "label": "food_dining", "source": "global", "country": "USA"},
{"text": "ambiguous narration", "label": "shopping_retail", "source": "finee", "country": "India"},
]
rows.extend(
{"text": f"food {i}", "label": "food_dining", "source": "global", "country": "USA"}
for i in range(30)
)
rows.extend(
{"text": f"transport {i}", "label": "transportation", "source": "global", "country": "USA"}
for i in range(30)
)
result = split_dataset(pd.DataFrame(rows), seed=19, test_size=.2, validation_size=.1)
partition_texts = set().union(
*(set(part["text"]) for part in (result.train, result.validation, result.test, result.india_holdout))
)
assert "ambiguous narration" not in partition_texts