describe()默认仅对数值列有效,分类列需用value_counts()查频次,数值列细节需布尔索引;扫读前先用nunique()判断取值多样性;空值检查须组合isna()与字符串判断,避免语义缺失。
用 Pandas 的 describe() 看列分布,但别指望它对所有类型都有效
describe() 是最常被点开的列分布快查方式,但它默认只对数值型列生效。如果你对一个含 object 类型(比如城市名、状态标签)的列调用它,返回结果里只有 count、unique、top、freq 四项——没有百分比,也没有排序逻辑,top 只是出现次数最多的那个值,不保证唯一。
实操建议:
- 想看分类列完整频次分布,必须换用
value_counts(),而不是硬套describe() - 加参数
normalize=True可直接得比例,比如df['status'].value_counts(normalize=True) - 数值列想看分位数以外的分布细节(如零值占比),
describe()也不够,得配合布尔索引:(df['age'] == 0).mean()
在 Jupyter 中用 df[col].head() + df[col].nunique() 快速判断列是否适合直接扫读
“结构界面直接浏览”这事,本质是人眼识别成本问题。一列有 5 个值,可以扫;有 2 万种取值,扫就是自我惩罚。
常见错误现象:双击列名进编辑器、或用 df[['col']].head(20) 拉出一堆重复又无序的内容,看不出规律。
实操建议:
- 先跑
df['category'].nunique()—— 如果远小于len(df),再用value_counts()看分布 - 如果
nunique()接近行数(比如 UUID、时间戳),放弃扫读,改用df['ts'].min(), df['ts'].max()看范围 - 对文本列,
df['text'].str.len().describe()比直接看前几行更能暴露空值、超长字段等隐性问题
用 pd.crosstab() 查两列组合分布,避免手动 groupby 计数出错
想快速知道「性别」和「是否付费」之间怎么交叉分布?很多人会写 df.groupby(['gender', 'paid']).size(),但结果是多级索引 Series,不好一眼定位比例,也难导出成表格。
实操建议:
-
pd.crosstab(df['gender'], df['paid'])直接生成二维表,行列带标签,支持normalize='index'算行占比 - 加
margins=True会自动加合计行/列,省去手算总数的步骤 - 注意:若某组组合频次为 0,
crosstab默认不显示该格子,要用dropna=False强制保留空组合
警惕 df.info() 里的 non-null 数字,它不告诉你空值具体长啥样
df.info() 显示每列非空数,看起来很省事。但 None、np.nan、空字符串 ''、字符串 'NULL' 都可能被当成“有值”,导致 non-null 偏高,误判数据质量。
实操建议:
- 检查空值不能只信
info(),要组合使用:df[col].isna().sum()(抓NaN/None) 和(df[col] == '').sum()(抓空字符串) - 对 object 列,
df[col].apply(type).value_counts()能揪出混入的float(其实是NaN)、int或list等异常类型 - 如果列里存在
'N/A'这类业务定义的空值,必须提前用replace()统一转为np.nan,否则后续所有分布统计都会失真
分布查看不是点开就完事的动作,关键在选对函数、看清返回值含义、以及意识到“空值”和“缺失语义”从来不是一回事。










