Python 数据问题复盘的标准流程

14次阅读

数据读取、类型推断、groupby 聚合和链式赋值是 pandas 四大易错点:需显式指定 encoding 与 sep;object 列常因混入 none/ 嵌套结构导致;groupby 注意 dropna 与 min_count;禁用 inplace,统一用赋值 +copy。

Python 数据问题复盘的标准流程

发现数据不一致时,先确认 pandas.read_csv 的编码和分隔符

很多“数据读出来就错”的问题,其实卡在第一行——read_csv 默认用 utf-8,但 Windows 记事本保存的 CSV 往往是 gbkgb2312;默认分隔符是逗号,可实际文件可能是制表符、分号,甚至中文顿号。不显式指定,pandas 就会硬拆,字段错位、数值变字符串、空值变 NaN 都是常态。

实操建议:

立即学习 Python 免费学习笔记(深入)”;

  • 用文本编辑器(如 VS Code)打开原始文件,右下角看真实编码和换行符类型
  • 优先试 encoding='gbk'sep='t',再根据报错信息调整
  • verbose=Truewarn_bad_lines=True(旧版)或 on_bad_lines='warn'(2.0+),让 pandas 吐出哪几行解析异常
  • 别依赖 encoding='utf-8-sig' 一招鲜——它只解决 BOM 头,对乱码无感

df.dtypes 显示 object 却不是字符串?检查是否混入了 Nonenp.nan 或嵌套结构

当某列本该是数字或日期,却显示 object 类型,大概率是这列里藏了非标数据:空字符串、None、字典、列表,甚至整行是 NaN。pandas 为保安全,自动降级为 object,后续 .str.dt 操作全失效。

实操建议:

立即学习 Python 免费学习笔记(深入)”;

  • df['col'].apply(type).value_counts() 直接看每行是什么类型
  • df['col'].isna().sum()df['col'].apply(lambda x: isinstance(x, (list, dict))).sum() 分别统计缺失和嵌套数量
  • 别急着 astype(str)——这会让 np.nan 变成字符串 'nan',后续清洗更难
  • 真要转字符串,用 df['col'].astype('string')(pandas 1.0+),它原生支持 pd.NA,不会污染数据

df.groupby().agg() 出结果为空或聚合失效?重点查 dropnamin_count

groupby 聚合后某组没结果,常见原因不是数据少,而是默认 dropna=True 把含 NaN 的组整个踢掉了;或者用 sum()mean() 时,整组全是 NaN,结果返回 NaN 而非 0,看着像“丢了数据”。

实操建议:

立即学习 Python 免费学习笔记(深入)”;

  • 加参数 dropna=False,确保空值也参与分组(尤其 categorical 列)
  • 数值聚合加 min_count=1,比如 .sum(min_count=1),避免全空组返回 NaN
  • 聚合函数传字典时,注意键是列名、值是函数名或列表:{'amount': ['sum', 'mean']},别写成 {'amount': sum}——后者会报 TypeError: cannot convert the series to <class></class>
  • 如果 groupby 键本身含 NaN,pandas 默认把它归为单独一组,但显示为 NaN 行——用 df.groupby(……, dropna=False).size() 才能看见它

复盘脚本跑一次就过,换数据就崩?必须隔离 inplace=True 和链式赋值

最隐蔽的坑是:你改着改着,发现某列突然变 None,或者 SettingWithCopyWarning 冒出来又消失,最后查半天发现是 df.drop(columns=['x'], inplace=True) 后,又写了 df['y'] = df['z'] * 2——而 df 其实是另一个 DataFrame 的视图,修改直接失效或引发未定义行为。

实操建议:

立即学习 Python 免费学习笔记(深入)”;

  • 彻底禁用 inplace=True:统一用 df = df.drop(……)df = df.fillna(……)
  • 链式操作务必用括号包住,比如 df = df.query('a > 0').assign(b=lambda x: x.a * 2),别拆成两行赋值
  • 对副本操作前,显式调用 .copy(),尤其是从大表切片后:subset = df[df.flag == 1].copy()
  • df._mgr.blocks(不推荐但有效)或 df.values.base is None 粗略判断是否视图——不过更稳的方式是:只要不确定,就 copy

数据复盘不是比谁写得快,是比谁漏得少。类型推断、空值传播、视图 / 副本边界——这些地方不出错,后面所有计算才真正可信。

text=ZqhQzanResources