Pandas 核心数据结构
学习目标
- 理解 Pandas 在数据分析中的地位
- 掌握 Series 的创建和基本操作
- 掌握 DataFrame 的创建和基本属性
- 理解索引(Index)机制
Pandas 是什么?
如果说 NumPy 是 Python 数据科学的引擎,那 Pandas 就是方向盘和仪表盘——它让你能方便地操控和观察数据。
Pandas 的核心能力:
| 能力 | 说明 |
|---|---|
| 数据读写 | 一行代码读取 CSV、Excel、JSON、SQL |
| 数据清洗 | 处理缺失值、重复值、异常值 |
| 数据筛选 | 像 SQL 一样灵活地过滤和查询数据 |
| 分组统计 | groupby 比纯 Python 循环快几十倍 |
| 数据合并 | 像 SQL JOIN 一样合并多张表 |
还记得第 1 章的预热练习吗?75 行纯 Python 代码做的事情,Pandas 5 行就搞定了。现在让我们正式学习它。
import pandas as pd
import numpy as np
print(pd.__version__) # 如 2.2.0
导入约定
和 NumPy 用 np 一样,Pandas 统一简写为 pd。
Series:带标签的一维数组
Series 是 Pandas 最基本的数据结构——你可以把它理解为一个带标签的 NumPy 数组。
创建 Series
import pandas as pd
# 从列表创建(自动生成 0, 1, 2... 索引)
s1 = pd.Series([85, 92, 78, 95, 88])
print(s1)
# 0 85
# 1 92
# 2 78
# 3 95
# 4 88
# dtype: int64
# 指定索引
s2 = pd.Series(
[85, 92, 78, 95, 88],
index=["语文", "数学", "英语", "物理", "化学"]
)
print(s2)
# 语文 85
# 数学 92
# 英语 78
# 物理 95
# 化学 88
# dtype: int64
# 从字典创建(键自动成为索引)
scores = {"语文": 85, "数学": 92, "英语": 78, "物理": 95}
s3 = pd.Series(scores)
print(s3)
Series 的结构
索引 (Index) 值 (Values)
─────────── ──────────
语文 85
数学 92
英语 78
物理 95
化学 88
每个 Series 都由两部分组成:
- 索引(Index):标签,用来定位数据
- 值(Values):实际数据,底层是 NumPy 数组
s = pd.Series([85, 92, 78], index=["语文", "数学", "英语"])
print(s.index) # Index(['语文', '数学', '英语'], dtype='object')
print(s.values) # [85 92 78] ← 这是一个 NumPy 数组!
print(s.dtype) # int64
print(s.shape) # (3,)
print(len(s)) # 3
Series 的访问
s = pd.Series([85, 92, 78, 95], index=["语文", "数学", "英语", "物理"])
# 用标签索引
print(s["数学"]) # 92
# 用位置索引
print(s.iloc[1]) # 92
# 切片
print(s["语文":"英语"]) # 标签切片(包含末尾!)
# 语文 85
# 数学 92
# 英语 78
# 布尔索引
print(s[s >= 90])
# 数学 92
# 物理 95
标签切片 vs 位置切片
- 标签切片
s["语文":"英语"]:包含末尾 - 位置切片
s.iloc[0:2]:不包含末尾(和 Python 列表一致)
这是新手容易混淆的地方。
Series 的运算
s = pd.Series([85, 92, 78, 95], index=["语文", "数学", "英语", "物理"])
# 向量化运算(和 NumPy 一样)
print(s + 5) # 每科加 5 分
print(s * 1.1) # 每科乘以 1.1
print(s.mean()) # 87.5 平均分
print(s.max()) # 95 最高分
print(s.describe()) # 一键生成描述性统计
DataFrame:带标签的二维表格
DataFrame 是 Pandas 的核心——你可以把它理解为一张Excel 表格,或者一个由多个 Series 组成的字典。
创建 DataFrame
# 方法 1:从字典创建(最常用)
data = {
"姓名": ["张三", "李四", "王五", "赵六", "钱七"],
"年龄": [22, 25, 23, 28, 21],
"城市": ["北京", "上海", "广州", "深圳", "杭州"],
"薪资": [15000, 22000, 18000, 25000, 16000]
}
df = pd.DataFrame(data)
print(df)
# 姓名 年龄 城市 薪资
# 0 张三 22 北京 15000
# 1 李四 25 上海 22000
# 2 王五 23 广州 18000
# 3 赵六 28 深圳 25000
# 4 钱七 21 杭州 16000
# 方法 2:从列表的列表创建
data = [
["张三", 22, "北京"],
["李四", 25, "上海"],
["王五", 23, "广州"]
]
df = pd.DataFrame(data, columns=["姓名", "年龄", "城市"])
# 方法 3:从 NumPy 数组创建
arr = np.random.randint(60, 100, size=(5, 3))
df = pd.DataFrame(arr, columns=["语文", "数学", "英语"])
# 方法 4:从 Series 字典创建
df = pd.DataFrame({
"数学": pd.Series([90, 85, 78], index=["张三", "李四", "王五"]),
"英语": pd.Series([88, 92, 75], index=["张三", "李四", "王五"])
})
DataFrame 的 结构
列 (Columns)
↓
索引 → 姓名 年龄 城市 薪资
(Index)
0 张三 22 北京 15000
1 李四 25 上海 22000
2 王五 23 广州 18000
3 赵六 28 深圳 25000
4 钱七 21 杭州 16000
DataFrame = 行索引(Index) + 列名(Columns) + 数据(Values)
基本属性
data = {
"姓名": ["张三", "李四", "王五", "赵六", "钱七"],
"年龄": [22, 25, 23, 28, 21],
"城市": ["北京", "上海", "广州", "深圳", "杭州"],
"薪资": [15000, 22000, 18000, 25000, 16000]
}
df = pd.DataFrame(data)
print(df.shape) # (5, 4) → 5 行 4 列
print(df.columns) # Index(['姓名', '年龄', '城市', '薪资'], dtype='object')
print(df.index) # RangeIndex(start=0, stop=5, step=1)
print(df.dtypes)
# 姓名 object ← 字符串
# 年龄 int64
# 城市 object
# 薪资 int64
print(df.size) # 20 → 5 × 4 = 20 个元素
print(len(df)) # 5 → 行数
快速查看数据
# 前 3 行
print(df.head(3))
# 后 2 行
print(df.tail(2))
# 基本信息
print(df.info())
# <class 'pandas.core.frame.DataFrame'>
# RangeIndex: 5 entries, 0 to 4
# Data columns (total 4 columns):
# # Column Non-Null Count Dtype
# --- ------ -------------- -----
# 0 姓名 5 non-null object
# 1 年龄 5 non-null int64
# 2 城市 5 non-null object
# 3 薪资 5 non-null int64
# 数值列的统计摘要
print(df.describe())
# 年龄 薪资
# count 5.000000 5.000000
# mean 23.800000 19200.000000
# std 2.774887 4147.288271
# min 21.000000 15000.000000
# 25% 22.000000 16000.000000
# 50% 23.000000 18000.000000
# 75% 25.000000 22000.000000
# max 28.000000 25000.000000
info() 和 describe() 是你的好朋友
拿到一份新数据,第一件事就是跑 df.info() 和 df.describe()——它们能让你在几秒内了解数据的"全貌"。
访问列
# 访问单列 → 返回 Series
print(df["姓名"])
# 0 张三
# 1 李四
# ...
# 也可以用点语法(列名不含空格且不与方法冲突时)
print(df.