3. 数据剖析与探索:用Pandas给你的数据做个“体检”
拿到一份历史数据,别急着动手清洗。我个人的习惯是——先“望闻问切”。
什么意思?就是先全面了解数据长什么样,有什么毛病,再对症下药。这一步,我们叫数据剖析与探索。说白了,就是给你的数据做个全面体检。
Pandas里有一整套工具,能让你快速摸清数据的底细。今天我就带你过一遍最常用的几个:head()、info()、describe()、shape和dtypes。
核心逻辑:先看整体结构,再看统计特征,最后定位异常。这是数据清洗的黄金三步。
3.1 先看整体:shape 和 dtypes
每次加载完数据,我第一件事就是敲两行代码:df.shape 和 df.dtypes。为什么?因为这两个东西能告诉你最基础的信息——数据有多大,每列是什么类型。
import pandas as pd
# 加载历史订单数据
df = pd.read_csv('orders_history.csv')
# 看形状
print(df.shape)
# 输出:(50000, 12) —— 5万行,12列
# 看字段类型
print(df.dtypes)
输出结果大概长这样:
| 字段名 | 类型 |
|---|---|
| order_id | int64 |
| customer_name | object |
| order_date | object |
| amount | float64 |
| status | object |
注意:看到 order_date 是 object 类型了吗?这说明日期被读成了字符串。我在项目中遇到过好几次,因为日期格式不统一,导致后续分析全乱套。所以这一步就能发现类型问题。
你想想看,如果 amount 字段显示的是 object 而不是 float64,那说明里面有脏数据——比如混入了"待确认"这样的文本。这就是清洗的信号。
3.2 快速预览:head() 和 tail()
head() 默认显示前5行。我习惯先看前5行,再看后5行,这样能快速感知数据的两端有没有异常。
# 看前5行
print(df.head())
# 看后5行
print(df.tail())
# 随机看10行(我特别喜欢这个)
print(df.sample(10))
为什么要用 sample()?因为有时候数据是按时间排序的,只看头尾可能漏掉中间的问题。随机抽样能帮你发现一些“隐藏的惊喜”。
小技巧:如果数据量很大(比如上百万行),head(100) 就够了。别傻乎乎地打印全部,你的终端会卡死的。我曾经手滑过一次……嗯,等了半分钟才缓过来。
3.3 全面体检:info()
info() 是我最常用的函数,没有之一。它一次性告诉你:总行数、每列的非空数量、数据类型、内存占用。简直就是数据体检报告。
print(df.info())
输出示例:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 50000 entries, 0 to 49999
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 order_id 50000 non-null int64
1 customer_name 49800 non-null object
2 order_date 50000 non-null object
3 amount 49500 non-null float64
4 status 49000 non-null object
dtypes: float64(1), int64(1), object(3)
memory usage: 4.6+ MB
看到问题了吗?customer_name 只有49800条非空,说明有200条缺失。status 更夸张,少了1000条。这些就是清洗的重点对象。
关键指标:Non-Null Count 如果小于总行数,就说明有缺失值。缺失比例超过5%的字段,要特别关注。
3.4 统计摘要:describe()
describe() 默认只对数值型列做统计。它会给出:计数、均值、标准差、最小值、四分位数、最大值。这些数字能帮你快速发现异常值。
print(df.describe())
输出示例:
| order_id | amount | |
|---|---|---|
| count | 50000.0 | 49500.0 |
| mean | 25000.5 | 356.78 |
| std | 14433.8 | 1200.45 |
| min | 1.0 | -500.0 |
| 25% | 12500.0 | 50.0 |
| 50% | 25000.0 | 150.0 |
| 75% | 37500.0 | 400.0 |
| max | 50000.0 | 99999.0 |
看到 amount 的最小值是 -500 了吗?金额怎么可能为负?这明显是异常值。再看最大值 99999,均值才356,这明显是个离群点。
避坑指南:我曾经接手过一份销售数据,describe() 显示某个字段的 max 值比 75% 分位数大了100倍。后来一查,是有人录入时多按了个0。这种错误靠肉眼根本看不出来,但统计摘要一眼就能发现。
如果想看非数值列的统计,可以加个参数:
print(df.describe(include='object'))
这样会显示:频次最高的值(top)、出现次数(freq)、唯一值个数(unique)。比如 status 字段,如果唯一值有50个,那肯定有问题——订单状态一般就三四种。
3.5 实战组合拳
好了,上面这些工具单独用都很简单。但真正的高手,是把它们组合起来用。我一般按这个顺序来:
- 先看 shape —— 确认数据量是否合理。比如预期10万行,结果只有1万行,那加载可能有问题。
- 再看 dtypes —— 检查类型是否匹配。日期要是字符串,赶紧转。
- 然后 info() —— 定位缺失值。哪些列缺了多少,心里有数。
- 接着 describe() —— 发现异常值。负金额、超大值、离谱的均值,都在这步暴露。
- 最后 head() + sample() —— 肉眼验证一下。看看数据长什么样,有没有明显的格式问题。
# 我的标准流程
def data_audit(df):
print("="*50)
print("1. 数据形状:", df.shape)
print("="*50)
print("\n2. 字段类型:")
print(df.dtypes)
print("\n3. 数据信息:")
df.info()
print("\n4. 数值统计:")
print(df.describe())
print("\n5. 前5行预览:")
print(df.head())
print("\n6. 随机抽样:")
print(df.sample(5))
我的习惯:把这个函数保存成脚本,每次拿到新数据先跑一遍。5秒钟就能知道数据健不健康。省下的时间,够你喝杯咖啡了。
说白了,数据剖析不是为了炫技,而是为了少走弯路。你想想看,如果连数据有多少缺失、类型对不对都不知道,就开始写清洗代码,那不是盲人摸象吗?
所以,拿到数据别急着动手。先体检,再开刀。这是数据工程师的基本素养。