Validating Date/Datetime columns imported as strings #396
|
Hi all, I'm trying to better understand the intended workflow for validating In my case, I'm importing data from Excel. If a date column contains a single invalid value (e.g. For example: import polars as pl
import dataframely as dy
class TestSchema(dy.Schema):
value = dy.Datetime(nullable=True)
df = pl.DataFrame(
{
"value": [
"banana",
"2026-03-18 00:00:00",
"2026-04-17 00:00:00",
None,
]
}
)
good, failures = TestSchema.filter(
df,
cast=True,
)
print(failures.invalid())Output: In this case, all non-null values are reported as invalid. I was wondering if I'm missing a step somewhere. I could pre-convert the column before validation, but that would replace invalid values with pl.col("value").str.to_datetime(strict=False)My goal is to identify invalid values while still validating that date/datetime strings are parseable. Given that, I'm not sure if I'm misunderstanding how Dataframely is intended to handle mixed-value columns that are imported as String. Is preprocessing the expected approach here, or is there a recommended Dataframely approach for handling this type of input? Any insight would be appreciated. Thank you |
Replies: 1 comment 1 reply
|
Preprocessing is the expected approach, but the reason all three rows come back invalid is worth spelling out, because it isn't the reason it looks like.
def _cast_if_required(expr, current_dtype, column, *, strict=True):
if column.validate_dtype(current_dtype):
return expr
return expr.cast(column.dtype, strict=strict)So what runs is DtypeCastRule(
pl.col(col_name).is_null()
== pl.col(f"{ORIGINAL_COLUMN_PREFIX}{col_name}").is_null()
)Non-null before the cast and null after counts as a cast failure. Your two well-formed datetime strings didn't survive For what you actually want, which is seeing the bad values rather than silently nulling them, I'd leave the column as a String in the schema and put the parse in a check: class TestSchema(dy.Schema):
value = dy.String(
nullable=True,
check=lambda expr: expr.str.to_datetime(strict=False).is_not_null(),
)
good, failures = TestSchema.filter(df)
typed = good.with_columns(pl.col("value").str.to_datetime())If you'd rather the schema hold the actual Datetime type, the alternative is to parse first with |
Preprocessing is the expected approach, but the reason all three rows come back invalid is worth spelling out, because it isn't the reason it looks like.
cast=Trueruns the frame throughmatch_to_schema(..., casting="lenient"), and lenient casting is literally this, from_match_to_schema.py:So what runs is
pl.col("value").cast(pl.Datetime, strict=False). That'scast, notstr.to_datetime, and in polars those aren't the same thing at all.castis not a date parser. Anything it can't turn into a Datetime become…