第二章:数据探索与概览——用Pandas给你的数据“把把脉”
拿到一份新数据,你会怎么做?
我个人的习惯是,先别急着写清洗逻辑。先看看数据长什么样,心里有个底。这就好比医生看病,总得先望闻问切吧?
数据探索,就是给数据做个体检。今天我们就聊聊,怎么用Pandas快速完成这个步骤。
2.1 数据概览:先看全貌
数据加载进来后,我通常会先调用.head()和.tail()。这俩函数能让你快速瞄一眼数据的头和尾。
import pandas as pd
df = pd.read_csv('sales_data.csv')
print(df.head()) # 默认显示前5行
print(df.tail(3)) # 显示最后3行
嗯,这里要注意。光看几行是不够的。你想想看,如果数据有100万行,前5行能代表全部吗?
所以,我还会用.shape看行列数,用.columns看列名。
print(f"数据集形状: {df.shape}")
print(f"列名列表: {df.columns.tolist()}")
我在项目中遇到过,有次数据明明有20列,但打印出来只有19个列名。后来发现,是列名里藏了个不可见字符。这种坑,光看head是看不出来的。
2.2 info()函数:数据类型的“体检报告”
info()是我最常用的函数之一。它就像一份体检报告,告诉你每列的数据类型、非空值数量、内存占用。
df.info()
输出大概长这样:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10000 entries, 0 to 9999
Data columns (total 8 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 user_id 10000 non-null int64
1 name 9998 non-null object
2 age 10000 non-null int64
3 salary 9500 non-null float64
4 join_date 10000 non-null object
5 department 9999 non-null object
6 score 8000 non-null float64
7 remark 5000 non-null object
dtypes: float64(2), int64(2), object(4)
memory usage: 625.0+ KB
看到这个,我脑子里会立刻冒出几个问题:
- name列少了2个值——有缺失,需要处理
- salary列只有9500个非空——缺失了500个,占比5%
- join_date是object类型——按理说应该是日期,得转换
- remark列只有一半有值——这列可能得考虑是否保留
核心要点:info()能帮你快速定位缺失值和类型错误。这是数据清洗的第一步,也是最重要的一步。
2.3 describe()函数:数值列的“统计摘要”
describe()默认只对数值列做统计。它会给出计数、均值、标准差、最小值、四分位数、最大值。
df.describe()
输出示例:
| age | salary | score | |
|---|---|---|---|
| count | 10000.0 | 9500.0 | 8000.0 |
| mean | 35.2 | 12500.0 | 78.5 |
| std | 12.1 | 8500.0 | 15.3 |
| min | 18 | 0.0 | 0.0 |
| 25% | 25 | 6000.0 | 70.0 |
| 50% | 33 | 10000.0 | 80.0 |
| 75% | 45 | 16000.0 | 90.0 |
| max | 120 | 999999.0 | 100.0 |
看到这个表,我一般会关注几个点:
- min和max是否合理——age最大120岁?这明显是异常值
- 均值和中位数是否接近——salary均值12500,中位数10000,说明有高薪拉高了平均
- count是否一致——score只有8000个,说明缺失了2000个
小技巧:如果想看所有列(包括非数值列)的统计,可以加个参数:df.describe(include='all')。这样字符串列也会显示频次、唯一值数量等信息。
2.4 数据类型检查:别让类型坑了你
数据类型不对,后面所有操作都可能出错。我建议用.dtypes查看每列的类型。
print(df.dtypes)
输出:
user_id int64
name object
age int64
salary float64
join_date object
department object
score float64
remark object
dtype: object
这里有个常见问题:日期列是object类型。如果不转换,你没法做日期运算。
# 转换日期列
df['join_date'] = pd.to_datetime(df['join_date'])
# 检查转换后的类型
print(df['join_date'].dtype) # 输出: datetime64[ns]
我曾经遇到过一个坑:某列看起来是数字,但类型是object。原因是数据里混入了逗号或空格。比如"1,234"这种写法,Pandas会把它当成字符串。
# 处理这种问题
df['salary'] = df['salary'].str.replace(',', '').astype(float)
注意:类型转换前,一定要先检查是否有无法转换的值。可以用pd.to_numeric(..., errors='coerce'),把无法转换的变成NaN。
2.5 知识体系:数据探索的核心逻辑
下面这张图,是我自己总结的数据探索流程。每次拿到新数据,我都会按这个顺序走一遍。
说白了,数据探索就是帮你建立对数据的直觉。你不需要记住所有细节,但要知道哪些地方可能有问题。
2.6 实战小贴士:我的习惯做法
最后,分享几个我自己的小习惯:
- 先跑info(),再看describe()——info告诉你有什么问题,describe告诉你问题有多严重
- 对每一列都问三个问题:类型对吗?有缺失吗?值范围合理吗?
- 别信数据,信统计——肉眼看到的5行数据,可能全是假象
我的经验:数据探索这一步,花的时间越多,后面清洗就越顺利。我曾经因为跳过这一步,直接写清洗逻辑,结果发现数据结构和预想完全不同,白干了两天。从那以后,我再也不敢省这一步了。
好了,数据探索就聊到这儿。记住,拿到数据先别急着动手,先看看它长什么样。这是数据清洗的第一步,也是最关键的一步。