Files
tianxuan/analysis/data_loader/_clean.py
T
PM-pinou 9f06e40a41 refactor: clean views/clustering.py and split data_loader.py into package
Task A: Replace _run_clustering_pipeline (533L->228L) — remove dead
docstring code, delegate to analysis.services.clustering.

Task B: Split analysis/data_loader.py (746L) into package:
  analysis/data_loader/
    __init__.py  — re-exports all public symbols
    _csv.py      — load_csv_directory, BOM/encoding detection
    _schema.py   — schema merging and validation
    _clean.py    — numeric coercion helper
    _sqlite.py   — save_to_db, load_from_db, load_from_db_lazy, etc.
  Keep old data_loader.py as thin re-export wrapper.

Verified: manage.py check (0 issues), run_pipeline (3 clusters, OK)
2026-07-24 13:52:07 +08:00

33 lines
1.3 KiB
Python

"""Data cleaning helpers: numeric coercion for string columns."""
import polars as pl
def _coerce_to_float(series: pl.Series) -> pl.Series:
"""Convert string series to Float64.
Every entry that doesn't parse as a valid float becomes null.
Handles blank strings, standalone '+'/'-', 'N/A', 'null', 'None', etc.
"""
series = series.cast(pl.Utf8).str.strip_chars()
artifacts = ('', '+', '-', '.', '..', 'N/A', 'n/a', 'NA', 'null', 'None', 'NULL', '?', '---', '--', '/')
is_artifact = series.is_in(pl.Series(artifacts).implode())
result = []
for v, bad in zip(series.to_list(), is_artifact.to_list()):
if v is None or bad:
result.append(None)
else:
# Check for "+"/"-" prefix artifacts (e.g., "+abc", "-xyz")
# where the value isn't a genuine numeric string. Values like
# "+5" or "-3.14" are still accepted as valid floats below.
if len(v) > 1 and v[0] in '+-':
try:
float(v[1:]) # validate suffix minus prefix
except ValueError:
result.append(None)
continue
try:
result.append(float(v))
except (ValueError, TypeError):
result.append(None)
return pl.Series(result, dtype=pl.Float64)