# Source: content/notes/libraries/pandas.md
# Independent CPU example; use the curriculum environment.
# See /notes/ml/#example-environment or /notes/deep-learning/#example-environment.

from io import StringIO
import numpy as np
import pandas as pd
raw = "user,value\na,10\nb,4\na,20\nb,6\n"
parts = [chunk.groupby("user")["value"].agg(["sum", "count"])
         for chunk in pd.read_csv(StringIO(raw), dtype={"user": "string", "value": "int64"}, chunksize=2)]
totals = pd.concat(parts).groupby(level=0).sum()
assert totals.loc["a", "sum"] == 30 and totals.loc["b", "count"] == 2
assert pd.isna(pd.Series([True, pd.NA], dtype="boolean").iloc[1])
assert (pd.NA & False) is False
local = pd.DatetimeIndex(["2025-03-09 01:30", "2025-03-09 03:30"])
utc = local.tz_localize("America/New_York", ambiguous="raise", nonexistent="raise").tz_convert("UTC")
assert utc[1] - utc[0] == pd.Timedelta("1h")
events = pd.DataFrame({"user": ["a", "a"], "time": pd.to_datetime(["2025-01-10", "2025-01-03"], utc=True)})
prices = pd.DataFrame({"user": ["a"], "available": pd.to_datetime(["2025-01-02"], utc=True), "price": [10.]})
joined = pd.merge_asof(events.sort_values("time"), prices.sort_values("available"),
    left_on="time", right_on="available", by="user", direction="backward", tolerance=pd.Timedelta("3D"))
assert len(joined) == len(events)
assert joined.price.iloc[0] == 10 and pd.isna(joined.price.iloc[1])
left = pd.DataFrame({"key": [1., np.nan]})
right = pd.DataFrame({"key": [np.nan], "value": [7]})
assert left.merge(right, on="key", how="left", validate="many_to_one").value.iloc[1] == 7
print("schema, chunk aggregation, nullable logic, DST, freshness, null-key checks passed")
