应在pandas链式操作关键节点用模块级logger.info记录shape、空值等指标,覆盖隐式nan,避免print和inplace,日志需带上下文id并立即采集计算结果。

怎么在 Pandas 流程里加轻量级日志
直接往 apply、groupby 或 pipe 链里插日志,别碰装饰器或全局钩子——太重,还容易干扰链式调用的返回值类型。
常见错误是用 print() 埋点:一跑分布式就消失,本地调试又刷屏;或者把日志塞进 lambda 里,结果异常堆栈指向 <lambda></lambda>,根本看不出在哪一步挂的。
- 用
logging.getLogger(__name__)获取模块级 logger,避免多进程下日志错乱 - 在关键节点(如清洗后、聚合前)调用
logger.info(f"shape: {df.shape}, nulls: {df.isnull().sum().to_dict()}")</li> <li>对耗时操作加 <code>time.time()差值,但只打到DEBUG级别,生产默认关掉 - 别记录整张
df.head(),改用df.dtypes.to_dict()+df.memory_usage(deep=True).sum()看结构和开销
为什么不该依赖 Jupyter cell 执行顺序做可观测性
Jupyter 的执行状态不可序列化,df 变量名重复、cell 重跑跳步、内核重启后断点失效——这些都会让“我刚才看到的中间态”变成玄学。
真实场景是:脚本要上 Airflow,或被同事复用,或需回溯某天凌晨三点失败的调度任务。这时候靠人脑记 cell 顺序等于没观测。
立即学习“Python免费学习笔记(深入)”;
使用模板与程序分离的方式构建,依靠专门设计的数据库操作类实现数据库存取,具有专有错误处理模块,通过 Email 实时报告数据库错误,除具有满足购物需要的全部功能外,成新商城购物系统还对购物系统体系做了丰富的扩展,全新设计的搜索功能,自定义成新商城购物系统代码功能代码已经全面优化,杜绝SQL注入漏洞前台测试用户名:admin密码:admin888后台管理员名:admin密码:admin888
- 每个处理步骤必须有明确输入/输出标识,比如
df_clean = clean_raw(df_raw),变量名带语义 - 把关键中间结果存成 Parquet(带时间戳),路径用
f"interim/{step_name}_{pd.Timestamp('now').strftime('%Y%m%d_%H%M%S')}.parquet" - 禁用
inplace=True,它会让日志里 “before/after” 对不上行数和索引 - 如果非要用 notebook,用
%store保存小对象(如统计字典),但别存DataFrame
如何让缺失值统计不漏掉隐式 NaN
df.isnull().sum() 漏掉字符串 "NULL"、整数 -999、空字符串 "" 这类业务约定的“伪空值”,导致可观测性报告失真——看起来数据很干净,实际下游模型炸了。
这不是 Pandas 的 bug,是业务语义没对齐。可观测性得覆盖“人认为的空”,不只是机器认为的 np.nan。
- 初始化时用
pd.read_csv(..., na_values=["NULL", "N/A", ""])主动转义 - 写个检查函数
check_implicit_nulls(df, null_patterns={"age": [-999], "city": ["", "UNKNOWN"]}),返回各列匹配数 - 把这类检查结果统一打到日志里,字段级标注 “implicit_nulls: 127”,比笼统说 “total nulls: 0” 有用得多
- 注意
object列里混数字字符串(如"1.5"和"missing"),astype(float)会静默转出np.nan,但原始字符串已丢失
当流程跑在 Dask 或 Spark 上时,日志位置容易错乱
Dask 的 client.submit() 或 Spark 的 rdd.map() 里打日志,大概率只在 worker 节点 stdout 输出,主进程收不到;更糟的是,多个 worker 同时写同一文件,日志互相覆盖。
不是日志没打,是你没找对地方看。
- 别用
print()或文件写入,统一走logging并配置handlers=[logging.StreamHandler(sys.stderr)],Dask/Spark 默认捕获 stderr - 给每条日志加上下文 ID:
log_id = str(uuid.uuid4())[:8],在 pipeline 入口生成,透传到所有子任务 - Spark 中避免在
map里调logger.info()太频繁,会被 driver 节点日志缓冲区截断;改用logging.getLogger("audit").log(15, ...)(自定义 level)分流 - Dask 的
client.get_scheduler_logs()可查调度层日志,但 worker 日志得去对应节点的/tmp/dask-worker-*.log找,别指望 Web UI 全显示
最常被忽略的一点:所有日志里的 DataFrame shape、内存占用、列名列表,都得在计算完成之后立刻采集。延迟采集(比如等整个 pipeline 结束再回头算)在 lazy-evaluation 引擎里会得到错误结果——因为中间 df 可能已被 GC 或重计算过。









