摘要
拿到一份数据后,不应该马上开始清洗、分组或建模。第一步应先认识数据集:有多少行、多少列、字段含义是什么、数据类型是否正确、缺失值分布如何、数值范围是否异常、分类字段有哪些取值。
本文围绕 pandas 的数据概览能力,介绍 head、info、describe、shape、dtypes、isna、value_counts、nunique 等常用方法,并通过一份订单数据示例,建立一套拿到数据后的探索检查流程。
一、背景与问题
很多数据分析错误不是出现在复杂算法,而是出现在最开始的数据理解阶段:
- 日期字段被当成字符串处理。
- 金额字段混入了空值、字符或异常负数。
- 分类字段存在大小写、空格和别名问题。
- 主键并不唯一,导致合并后数据量膨胀。
- 缺失值集中在某些业务状态中,被误认为随机缺失。
- 统计指标直接基于脏数据计算,导致结论偏差。
因此,数据分析的第一步不是“算结果”,而是回答几个基础问题:
这份数据有多大?
每一列是什么含义?
类型是否符合业务预期?
有没有缺失、重复和异常?
关键字段的分布是否合理?
是否可以支撑后续分析目标?
数据概览就是在正式处理前建立对数据的第一层认知。
二、核心概念
1. 数据规模
数据规模包括行数、列数、内存占用和字段数量。pandas 中常用:
| df.shape | 查看行数和列数 |
| df.columns | 查看列名 |
| df.info() | 查看非空数量、类型和内存 |
| df.memory_usage() | 查看内存占用 |
规模决定了后续处理方式。几千行数据可以直接交互式分析,几千万行数据则需要分块、数据库或更高性能工具。
2. 字段类型
字段类型决定能否进行正确计算:
- 金额和数量应是数值类型。
- 日期应转换为日期时间类型。
- 状态、地区、渠道适合作为分类字段。
- ID 字段通常应作为字符串处理,而不是数值。
ID 如果被当作数字,可能丢失前导零,例如订单号 000123 变成 123。
3. 缺失值
缺失值并不一定是错误。它可能表示:
- 业务上尚未发生。
- 数据采集失败。
- 用户未填写。
- 某些类型的记录没有该字段。
- 系统迁移导致历史数据不完整。
处理缺失值前,必须先理解缺失原因。
4. 分布与异常
数据分布帮助判断字段是否合理。例如:
- 金额是否出现负数。
- 年龄是否超过合理范围。
- 状态字段是否出现未知值。
- 日期是否超出分析窗口。
- 某个渠道是否占比异常高。
探索阶段不一定立即修复问题,但要记录所有可疑点。
三、工作原理
1. 数据探索流程
一套通用流程如下:
读取数据
→ 查看样例行
→ 检查规模和列名
→ 检查数据类型
→ 检查缺失值
→ 检查重复值
→ 检查数值分布
→ 检查分类字段取值
→ 记录数据问题
探索流程的目标不是把所有问题一次性解决,而是形成数据画像。
2. 样例行的价值
head() 和 tail() 可以快速观察数据格式,但不要只看前几行就下结论。很多数据文件前几行可能是特殊样本,例如测试数据、历史数据或导出说明。
可以随机抽样查看:
df.sample(5, random_state=42)
随机样本更容易暴露字段格式不一致的问题。
3. 统计描述的边界
describe() 对数值列非常有用,但它只能提供基础统计。平均值、最大值和最小值不能替代业务判断。例如订单金额最大值很大,可能是大客户订单,也可能是金额单位错误。
4. 探索结果应可复用
数据探索不应只停留在 Notebook 输出中。可以将关键检查封装为函数,形成每次读取数据后的固定检查流程。
四、实战示例
1. 准备示例数据
from pathlib import Path
import pandas as pd
data_dir = Path("data")
data_dir.mkdir(exist_ok=True)
orders = pd.DataFrame(
{
"order_id": ["A001", "A002", "A003", "A004", "A004", "A006"],
"customer": ["Alice", "Bob", "Carol", "David", "David", None],
"region": ["华东", "华南", "华东", "华北", "华北", "华东 "],
"amount": [1200.0, 800.0, 1560.0, –20.0, –20.0, None],
"status": ["paid", "pending", "paid", "cancelled", "cancelled", "Paid"],
"order_date": [
"2026-09-01",
"2026-09-02",
"2026-09-03",
"2026-09-04",
"2026-09-04",
"bad-date",
],
}
)
orders.to_csv(data_dir / "orders.csv", index=False, encoding="utf-8-sig")
这份数据故意包含重复订单、缺失客户、负金额、状态大小写不一致、地区空格和错误日期。
2. 读取数据并查看样例
import pandas as pd
df = pd.read_csv("data/orders.csv")
print(df.head())
print(df.tail())
print(df.sample(3, random_state=42))
样例查看主要用于确认列名、字段内容和明显格式问题。
3. 查看规模和字段
print("shape:", df.shape)
print("columns:", df.columns.tolist())
print(df.info())
info() 中的非空数量可以快速判断哪些列存在缺失。对象类型列需要继续判断是字符串、混合类型还是日期未转换。
4. 检查数据类型
print(df.dtypes)
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
df["order_date"] = pd.to_datetime(df["order_date"], errors="coerce")
print(df.dtypes)
转换后应重新检查缺失值,因为无法解析的数据会被转换为缺失。
5. 缺失值分析
missing_count = df.isna().sum()
missing_rate = df.isna().mean().sort_values(ascending=False)
print(missing_count)
print(missing_rate)
缺失率高的字段不一定要删除,先判断它是否对当前分析目标关键。
6. 重复值检查
print("duplicated rows:", df.duplicated().sum())
print("duplicated order_id:", df["order_id"].duplicated().sum())
print(df.loc[df["order_id"].duplicated(keep=False)])
整行重复和业务主键重复是两类不同问题。主键重复可能意味着重复导出、拆单、退款记录或数据错误。
7. 数值字段概览
print(df["amount"].describe())
print(df.loc[df["amount"] < 0, ["order_id", "amount", "status"]])
负金额可能是退款,也可能是错误录入。探索阶段应把它标记出来,后续根据业务规则处理。
8. 分类字段分布
print(df["status"].value_counts(dropna=False))
print(df["region"].value_counts(dropna=False))
状态字段中 paid 和 Paid 可能表示同一个含义,地区字段中的 华东 和 华东 也可能因为空格被当成不同值。
9. 字符串标准化预览
preview = df.copy()
preview["status_clean"] = preview["status"].str.strip().str.lower()
preview["region_clean"] = preview["region"].str.strip()
print(preview["status_clean"].value_counts(dropna=False))
print(preview["region_clean"].value_counts(dropna=False))
先做预览,不急着覆盖原字段。确认规则正确后,再进入正式清洗阶段。
10. 封装探索函数
def profile_dataframe(frame: pd.DataFrame) –> dict:
return {
"shape": frame.shape,
"columns": frame.columns.tolist(),
"dtypes": frame.dtypes.astype(str).to_dict(),
"missing_count": frame.isna().sum().to_dict(),
"missing_rate": frame.isna().mean().round(4).to_dict(),
"duplicated_rows": int(frame.duplicated().sum()),
}
profile = profile_dataframe(df)
print(profile)
封装后可以对不同数据文件重复使用,也可以输出为 JSON 或 Markdown 报告。
11. 输出数据概览报告
from pathlib import Path
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
summary = pd.DataFrame(
{
"dtype": df.dtypes.astype(str),
"missing_count": df.isna().sum(),
"missing_rate": df.isna().mean(),
"unique_count": df.nunique(dropna=True),
}
)
summary.to_csv(output_dir / "data_profile.csv", encoding="utf-8-sig")
print(summary)
这种字段级报告适合放进数据交付流程,用于和业务同学确认字段质量。
五、常见问题与实践建议
1. 为什么不能只看 head()?
前几行可能恰好很干净,不能代表整体。建议结合 sample()、缺失值统计、分类分布和数值描述一起判断。
2. describe() 是否能发现所有异常?
不能。它只能帮助发现明显的数值极端值。分类值拼写错误、日期解析失败、主键重复、业务状态非法,需要单独检查。
3. 缺失值是否应该全部填 0?
不应该。0 是一个有意义的数值,缺失表示未知或不存在。把缺失值填 0 可能改变统计结果。应根据字段语义决定填充、删除、保留或单独标记。
4. 为什么 ID 字段建议读成字符串?
ID 可能包含前导零、字母、连接符或超长数字。读成数值可能导致格式丢失或精度问题。订单号、手机号、身份证号等通常都应该按字符串处理。
5. 探索阶段要不要直接修改数据?
建议先生成问题清单和预览结果,再进入正式清洗。探索和清洗分开,可以减少误修改,也便于复盘每条规则的原因。
六、进阶思考
1. 建立数据字典
数据字典至少包含:
| 字段名 | 数据文件中的列名 |
| 中文含义 | 字段业务解释 |
| 数据类型 | 字符串、数值、日期等 |
| 是否必填 | 是否允许缺失 |
| 取值范围 | 合法值或范围 |
| 示例 | 典型样例 |
没有数据字典时,分析人员容易依靠猜测解释字段。
2. 用规则沉淀数据质量检查
探索阶段发现的问题,可以逐步变成数据质量规则:
order_id 不允许为空
order_id 在订单主表中应唯一
amount 不允许为空
amount 允许为负数时必须对应退款状态
order_date 必须能解析为日期
status 必须属于预定义枚举
这些规则后续可以用测试或数据质量工具自动执行。
3. 从探索到自动化
手工探索适合新数据集。稳定数据源应逐步自动化:
数据读取
→ 字段检查
→ 类型检查
→ 质量规则
→ 输出概览报告
→ 进入清洗流程
这样每次数据更新后都能快速发现异常。
4. 注意样本偏差
如果数据来自抽样、筛选或某个时间窗口,概览结果只代表当前样本。报告中应记录数据范围、抽样方式和数据来源。
结论
认识数据集是数据分析的第一步。通过 pandas 的 shape、info、dtypes、isna、describe、value_counts、nunique 等方法,可以快速建立数据画像,发现缺失、重复、类型错误和异常分布。
下一篇将进入数据读取实践,系统讲解 CSV、Excel 和数据库数据如何读入 pandas,并处理编码、日期、类型和大文件问题。
网硕互联帮助中心
评论前必须登录!
注册