第二章:数据探索与概览——用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()

输出示例:

agesalaryscore
count10000.09500.08000.0
mean35.212500.078.5
std12.18500.015.3
min180.00.0
25%256000.070.0
50%3310000.080.0
75%4516000.090.0
max120999999.0100.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 知识体系:数据探索的核心逻辑

下面这张图,是我自己总结的数据探索流程。每次拿到新数据,我都会按这个顺序走一遍。

数据探索核心流程 加载数据 概览:head() / shape info():类型与缺失 describe():统计摘要 检查要点 • 行数列数是否匹配 • 列名是否有异常 • 数据类型是否正确 • 缺失值数量 • 数值范围是否合理 • 均值与中位数差异 • 异常值初步判断 • 是否需要类型转换

说白了,数据探索就是帮你建立对数据的直觉。你不需要记住所有细节,但要知道哪些地方可能有问题。

2.6 实战小贴士:我的习惯做法

最后,分享几个我自己的小习惯:

  1. 先跑info(),再看describe()——info告诉你有什么问题,describe告诉你问题有多严重
  2. 对每一列都问三个问题:类型对吗?有缺失吗?值范围合理吗?
  3. 别信数据,信统计——肉眼看到的5行数据,可能全是假象

我的经验:数据探索这一步,花的时间越多,后面清洗就越顺利。我曾经因为跳过这一步,直接写清洗逻辑,结果发现数据结构和预想完全不同,白干了两天。从那以后,我再也不敢省这一步了。

好了,数据探索就聊到这儿。记住,拿到数据先别急着动手,先看看它长什么样。这是数据清洗的第一步,也是最关键的一步。

专注资料整理