Download dataforge/repairers/missing_value.py from Praneshrajan15/dataforge-playground: direct link, hf CLI and curl.
- Browser
- Download file 4.51 kB
-
https://huggingface.co/spaces/Praneshrajan15/dataforge-playground/resolve/main/dataforge/repairers/missing_value.py
- Command line
-
hf download hf://spaces/Praneshrajan15/dataforge-playground/dataforge/repairers/missing_value.py
-
curl -L -o missing_value.py https://huggingface.co/spaces/Praneshrajan15/dataforge-playground/resolve/main/dataforge/repairers/missing_value.py
4.51 kB
| """Repairer for missing values via functional-dependency-derivable fills only. | |
| A missing value cannot be invented. This repairer fills a missing cell only | |
| when its value is *derivable* from a declared functional dependency: if some FD | |
| ``determinant -> this_column`` holds and another row shares the same determinant | |
| values with a known (non-missing) value in this column, that value is proposed. | |
| Otherwise it abstains (returns ``None``) - the missing value stays | |
| detection-only. Every proposal still passes the SMT verifier and constitution. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any | |
| from dataforge.detectors.base import Issue, Schema | |
| from dataforge.detectors.missing_value import is_missing | |
| from dataforge.repairers.base import ProposedFix, RetryContext | |
| from dataforge.table import TableLike, cell_value, column_names, row_count | |
| from dataforge.transactions.txn import CellFix | |
| class MissingValueRepairer: | |
| """Fills missing values only when a functional dependency makes them derivable.""" | |
| def propose( | |
| self, | |
| issue: Issue, | |
| df: TableLike, | |
| schema: Schema | None, | |
| retry_context: RetryContext | None = None, | |
| ) -> ProposedFix | None: | |
| """Propose an FD-derived fill, or abstain when the value is not derivable.""" | |
| del retry_context | |
| if issue.issue_type != "missing_value" or schema is None: | |
| return None | |
| fds = getattr(schema, "functional_dependencies", None) | |
| if not fds: | |
| return None | |
| old_value = cell_value(df, issue.row, issue.column) | |
| columns = set(column_names(df)) | |
| derived = self._derive_from_fds(df, issue.row, issue.column, fds, columns) | |
| if derived is None or is_missing(derived) or derived == old_value: | |
| return None | |
| return ProposedFix( | |
| fix=CellFix( | |
| row=issue.row, | |
| column=issue.column, | |
| old_value=old_value, | |
| new_value=derived, | |
| detector_id="missing_value", | |
| operation="update", | |
| ), | |
| reason=( | |
| f"Filled missing value in '{issue.column}' from a functional " | |
| f"dependency match -> '{derived}'." | |
| ), | |
| confidence=issue.confidence, | |
| provenance="deterministic", | |
| ) | |
| def _derive_from_fds( | |
| self, | |
| df: TableLike, | |
| row: int, | |
| column: str, | |
| fds: Any, | |
| columns: set[str], | |
| ) -> str | None: | |
| """Return a uniquely FD-derived value for the cell, or None.""" | |
| candidates: set[str] = set() | |
| for fd in fds: | |
| dependent = str(getattr(fd, "dependent", "")) | |
| determinant = [str(c) for c in getattr(fd, "determinant", [])] | |
| if dependent != column or not determinant: | |
| continue | |
| if any(col not in columns for col in determinant): | |
| continue | |
| key = self._row_key(df, row, determinant) | |
| if key is None: | |
| continue # determinant itself has a missing value; cannot match | |
| match = self._lookup(df, determinant, key, column) | |
| if match is not None: | |
| candidates.add(match) | |
| # Only fill when every matching FD agrees on a single value. | |
| return next(iter(candidates)) if len(candidates) == 1 else None | |
| def _row_key(df: TableLike, row: int, determinant: list[str]) -> tuple[str, ...] | None: | |
| """Return the determinant key for a row, or None if any part is missing.""" | |
| values: list[str] = [] | |
| for col in determinant: | |
| value = cell_value(df, row, col) | |
| if is_missing(value): | |
| return None | |
| values.append(value) | |
| return tuple(values) | |
| def _lookup( | |
| df: TableLike, determinant: list[str], key: tuple[str, ...], column: str | |
| ) -> str | None: | |
| """Find a non-missing dependent value for another row with the same key.""" | |
| found: set[str] = set() | |
| for other in range(row_count(df)): | |
| if tuple(cell_value(df, other, col) for col in determinant) != key: | |
| continue | |
| value = cell_value(df, other, column) | |
| if not is_missing(value): | |
| found.add(value) | |
| return next(iter(found)) if len(found) == 1 else None | |