引言

Python 凭借其简洁的语法和强大的生态,已成为数据科学领域的首选语言。而在数据处理与分析这个核心环节中,Pandas 几乎是你无法绕过的存在。无论你面对的是琐碎的表格整理、混乱的缺失值清洗,还是复杂的多源数据融合,Pandas 都能以优雅且高效的方式完成任务。

本文将为你提供一份全方位无死角的 Pandas 学习指南。从核心数据结构到高级技巧,每一节都配有即刻可运行的代码示例与输出,力求让你既能看懂,又能真正用起来。无论你是零基础小白,还是希望系统梳理知识体系的开发者,这篇长文都将成为你收藏夹里的案头参考。

目录

1. Pandas 简介

2. 快速安装与导入

3. 核心数据结构

3.1 Series

3.2 DataFrame

4. 数据读取与写入

4.1 CSV 与文本文件

4.2 Excel 文件

4.3 SQL 数据库

4.4 其他格式

5. 数据查看与基本属性

6. 数据选择与过滤

6.1 列选择

6.2 行选择:loc 与 iloc

6.3 布尔索引

6.4 query() 方法

7. 数据清洗

7.1 缺失值处理

7.2 重复值处理

7.3 数据类型转换

7.4 值替换

7.5 字符串操作

8. 数据变换与函数应用

8.1 apply / applymap / map

8.2 排序

8.3 分组聚合:groupby

8.4 数据透视表与交叉表

8.5 合并与连接

8.6 重塑与轴向旋转

9. 时间序列处理

9.1 日期解析与生成

9.2 时间索引与切片

9.3 重采样(Resample)

9.4 移动窗口与移位

10. 数据可视化

11. 进阶技巧与性能调优

11.1 巧用 category 减少内存

11.2 eval() 与 query() 加速

11.3 避免 SettingWithCopyWarning

11.4 分块读取超大文件

12. 总结与学习路径


1. Pandas 简介

Pandas 是 Python 中基于 NumPy 构建的数据分析库,其名字源自 “Panel Data”(面板数据)。它提供了两大核心数据结构——Series(一维)和 DataFrame(二维),让你可以像操作 Excel 表格一样轻松地处理结构化数据。主要功能包括:

  • 灵活的数据读写(CSV、Excel、SQL、JSON 等)

  • 高效的数据清洗与转换

  • 强大的分组聚合与透视表

  • 便捷的时间序列处理

  • 集成 Matplotlib 的快速可视化

2. 快速安装与导入

使用 pip 安装(建议同时安装可视化依赖):

pip install pandas matplotlib openpyxl

导入惯例:

import pandas as pd
import numpy as np

3. 核心数据结构

Pandas 的两大核心是 SeriesDataFrame,所有操作都围绕它们展开。

3.1 Series

Series 是一维带标签的数组,可以容纳不同类型的数据。

# 由列表创建,自动生成整数索引
s = pd.Series([10, 20, 30, 40])
print(s)

输出:

0    10
1    20
2    30
3    40
dtype: int64
# 自定义索引
s = pd.Series([0.5, 1.2, 2.7], index=['a', 'b', 'c'])
print(s['b'])

输出:1.2

# 通过字典创建,key 即为索引
s_dict = pd.Series({'北京': 2154, '上海': 2487, '广州': 1867})
print(s_dict)

3.2 DataFrame

DataFrame 是二维表格型结构,可以看作由多个 Series 组合而成。

创建方式极其灵活

# 通过字典创建(最常用)
df = pd.DataFrame({
    '名字': ['张三', '李四', '王五'],
    '年龄': [25, 30, 22],
    '城市': ['北京', '上海', '广州']
})
print(df)

输出:

   名字  年龄  城市
0  张三  25  北京
1  李四  30  上海
2  王五  22  广州
# 由列表嵌套创建
df_list = pd.DataFrame([[1, 2], [3, 4]], columns=['A', 'B'])
​
# 由 NumPy 数组创建
df_np = pd.DataFrame(np.random.randn(3, 2), columns=['col1', 'col2'])

4. 数据读取与写入

Pandas 支持读写数十种文件格式,以下是最常用的场景。

4.1 CSV 与文本文件

# 读取 CSV,默认以逗号分隔
df = pd.read_csv('data.csv')
​
# 常用参数一网打尽
df = pd.read_csv(
    'data.tsv',
    sep='\t',              # 分隔符
    header=0,              # 指定列名所在行
    names=['A', 'B', 'C'],  # 自定义列名
    index_col=0,           # 指定索引列
    usecols=['A', 'C'],    # 只读取部分列
    dtype={'A': 'str'},    # 指定数据类型
    parse_dates=['date'],  # 解析日期列
    na_values=['NULL'],    # 自定义缺失值标识
    encoding='utf-8'
)
​
# 写入 CSV
df.to_csv('output.csv', index=False)  # 不保存索引

4.2 Excel 文件

# 读取 Excel(需安装 openpyxl 或 xlrd)
df = pd.read_excel('workbook.xlsx', sheet_name='Sheet1')
​
# 读取所有 Sheet,返回字典 {sheet_name: DataFrame}
all_sheets = pd.read_excel('workbook.xlsx', sheet_name=None)
​
# 写入 Excel,可同时写多个 Sheet
with pd.ExcelWriter('output.xlsx') as writer:
    df1.to_excel(writer, sheet_name='用户', index=False)
    df2.to_excel(writer, sheet_name='订单', index=False)

4.3 SQL 数据库

from sqlalchemy import create_engine
engine = create_engine('sqlite:///example.db')  # 或 mysql+pymysql://...
​
# 读取 SQL 查询
df = pd.read_sql('SELECT * FROM users', con=engine)
​
# 写入数据库
df.to_sql('users_backup', con=engine, if_exists='replace', index=False)

4.4 其他格式

# JSON
df = pd.read_json('data.json')
# 剪贴板(直接复制表格到剪贴板后读取,调试神器)
df = pd.read_clipboard()
# HTML 中的表格
df_list = pd.read_html('https://example.com/page.html')

5. 数据查看与基本属性

拿到 DataFrame 后,第一件事就是“看一眼”。

df = pd.DataFrame({
    'A': [1, 2, 3, 4, 5],
    'B': [5.1, 6.2, 7.3, 8.4, 9.5],
    'C': ['x', 'y', 'z', 'x', 'y']
})
​
# 前 3 行
print(df.head(3))
​
# 后 2 行
print(df.tail(2))
​
# 数据集整体信息(非空值数量、数据类型、内存占用)
df.info()
​
# 数值列的基本统计指标(均值、标准差、四分位数等)
print(df.describe())
​
# 形状、列名、索引
print(df.shape)      # (5, 3)
print(df.columns)    # Index(['A', 'B', 'C'], dtype='object')
print(df.index)      # RangeIndex(start=0, stop=5, step=1)
​
# 快速统计唯一值
print(df['C'].unique())          # ['x' 'y' 'z']
print(df['C'].value_counts())    # 每个值出现的次数

6. 数据选择与过滤

这是数据操作中最频繁的部分,Pandas 提供了多层过滤手段。

6.1 列选择

# 单列(返回 Series)
age = df['年龄']
​
# 多列(返回 DataFrame)
subset = df[['名字', '城市']]

6.2 行选择:loc 与 iloc

  • loc:基于标签(索引名)选择

  • iloc:基于整数位置选择

df = pd.DataFrame({
    '成绩': [88, 92, 75, 60],
    '等级': ['B', 'A', 'C', 'D']
}, index=['张三', '李四', '王五', '赵六'])
​
# loc 标签切片(包含右端点)
print(df.loc['李四':'王五'])
# 输出:
#       成绩 等级
# 李四  92   A
# 王五  75   C
​
# loc 选择特定行和列
print(df.loc[['张三', '赵六'], ['成绩']])
​
# iloc 位置切片(不含右端点)
print(df.iloc[1:3])    # 第 2、3 行
print(df.iloc[0, 1])   # 第 1 行第 2 列的值 → 'B'

6.3 布尔索引

根据条件筛选行,Pandas 的杀手级特性。

# 单一条件
high_score = df[df['成绩'] >= 85]
​
# 多条件:必须使用 & (与)、| (或),并用括号包裹
filtered = df[(df['成绩'] > 70) & (df['等级'] != 'D')]
​
# isin 过滤
target_names = ['张三', '王五']
result = df[df.index.isin(target_names)]
​
# between 区间筛选
mid_score = df[df['成绩'].between(70, 90)]

6.4 query() 方法

让筛选条件更接近自然语言,尤其适合长条件语句。

df.query('成绩 > 80 and 等级 == "A"')

对于变量引用,使用 @

threshold = 80
df.query('成绩 > @threshold')

7. 数据清洗

现实世界的数据总是脏的,Pandas 是清洁工的最佳工具。

7.1 缺失值处理

df = pd.DataFrame({
    'A': [1, np.nan, 3],
    'B': [4, 5, np.nan],
    'C': ['cat', 'dog', np.nan]
})
​
# 检测缺失值
print(df.isnull())      # 布尔表
print(df.isnull().sum())  # 每列缺失值计数
​
# 删除含有缺失值的行
df_drop = df.dropna()            # 默认删除任何含 NaN 的行
df_drop_cols = df.dropna(axis=1)  # 删除含 NaN 的列
df_drop_sub = df.dropna(subset=['A', 'C'])  # 只考虑指定列
​
# 填充缺失值
df_fill = df.fillna(0)                      # 常数填充
df_fill_method = df.fillna(method='ffill')   # 向前填充(用上一个值)
# 高级填充:按列均值、自定义字典
df['A'] = df['A'].fillna(df['A'].mean())
df.fillna({'A': 0, 'C': 'unknown'}, inplace=True)

7.2 重复值处理

df = pd.DataFrame({
    'id': [1, 2, 2, 3],
    'name': ['Alice', 'Bob', 'Bob', 'Charlie']
})
​
# 检测重复行
print(df.duplicated())           # 返回布尔 Series
print(df.duplicated(subset='id'))  # 按特定列检测
​
# 删除重复项,保留第一次出现
df_unique = df.drop_duplicates()
df_unique_id = df.drop_duplicates(subset='id', keep='last')

7.3 数据类型转换

df = pd.DataFrame({'age': ['25', '30', '22'], 'score': ['88.5', '76.2', '90.1']})
​
# astype 转换
df['age'] = df['age'].astype(int)
​
# pd.to_numeric 更安全,可将无效值转为 NaN
df['score'] = pd.to_numeric(df['score'], errors='coerce')
​
# 转换为 category 类型节省内存
df['gender'] = df['gender'].astype('category')

7.4 值替换

df = pd.DataFrame({'grade': ['A', 'B', 'C', 'A-']})
# 单值替换
df['grade'] = df['grade'].replace('A-', 'A')
# 多值替换
df['grade'] = df['grade'].replace({'B': '良好', 'A': '优秀'})
# 使用正则
df['text'] = df['text'].replace(r'\d+', '', regex=True)

7.5 字符串操作

通过 .str 访问器,你可以对字符串列直接进行向量化处理。

s = pd.Series(['张三', '李四', '王五'])
# 拼接、切片、转换
print(s.str.cat(sep='、'))      # 张三、李四、王五
print(s.str.contains('三'))     # [True, False, False]
print(s.str.replace('王', '汪')) # 汪五
​
# 现实场景:清洗姓名中的空格
df['name'] = df['name'].str.strip().str.title()

8. 数据变换与函数应用

8.1 apply / applymap / map

  • map:Series 专用,根据字典或函数映射值

  • apply:DataFrame 的行/列应用函数,或 Series 元素级应用

  • applymap:DataFrame 的逐元素应用函数

df = pd.DataFrame({'A': [1, 2, 3], 'B': [10, 20, 30]})
​
# map 举例
df['A_label'] = df['A'].map({1: '低', 2: '中', 3: '高'})
​
# apply 对列(axis=0,默认)求极差
range_col = df[['A', 'B']].apply(lambda x: x.max() - x.min())
print(range_col)
​
# apply 逐元素用法(等价于 map)
df['B_sqrt'] = df['B'].apply(np.sqrt)
​
# applymap 格式化所有数字
df_formatted = df.applymap(lambda x: f'{x:.2f}')

8.2 排序

df = pd.DataFrame({
    'name': ['b', 'a', 'c'],
    'value': [20, 10, 30]
})
​
# 按值排序
df_sorted = df.sort_values('value', ascending=False)
​
# 多列排序
df_sorted_multi = df.sort_values(['name', 'value'], ascending=[True, False])
​
# 按索引排序
df_index_sorted = df.sort_index()

8.3 分组聚合:groupby

这是数据分析工作流的核心,“分组-应用-聚合”三步走。

df = pd.DataFrame({
    '部门': ['销售', '销售', '技术', '技术', '技术'],
    '员工': ['A', 'B', 'C', 'D', 'E'],
    '薪资': [8000, 9000, 12000, 11000, 15000]
})
​
# 简单分组求均值
dept_avg = df.groupby('部门')['薪资'].mean()
print(dept_avg)
# 输出:
# 部门
# 技术    12666.66
# 销售     8500.00
​
# agg 同时执行多个聚合
stats = df.groupby('部门').agg({
    '薪资': ['mean', 'max', 'min', 'count'],
    '员工': 'count'
})
print(stats)
​
# transform 将聚合结果广播回原形状
df['部门平均薪资'] = df.groupby('部门')['薪资'].transform('mean')
print(df)
​
# filter 按组过滤(例如只要人数大于2的部门)
df_filtered = df.groupby('部门').filter(lambda g: len(g) > 2)

8.4 数据透视表与交叉表

df = pd.DataFrame({
    '日期': ['1月', '1月', '2月', '2月'],
    '产品': ['苹果', '香蕉', '苹果', '香蕉'],
    '销量': [100, 80, 120, 90]
})
​
# pivot_table
pivot = pd.pivot_table(
    df, values='销量', index='日期', columns='产品',
    aggfunc='sum', fill_value=0
)
print(pivot)
# 输出:
# 产品  苹果  香蕉
# 日期
# 1月  100   80
# 2月  120   90
​
# 交叉表:计算频率
df_stack = pd.DataFrame({
    '性别': ['男', '女', '男', '女'],
    '学历': ['本科', '本科', '硕士', '硕士']
})
cross = pd.crosstab(df_stack['性别'], df_stack['学历'])
print(cross)

8.5 合并与连接

left = pd.DataFrame({'key': ['K0', 'K1', 'K2'], 'A': ['A0', 'A1', 'A2']})
right = pd.DataFrame({'key': ['K0', 'K1', 'K3'], 'B': ['B0', 'B1', 'B3']})
​
# merge 类似 SQL 的 JOIN
inner = pd.merge(left, right, on='key', how='inner')
left_join = pd.merge(left, right, on='key', how='left')
​
# concat 轴向拼接
df1 = pd.DataFrame({'A': [1, 2]})
df2 = pd.DataFrame({'A': [3, 4]})
concat_vertical = pd.concat([df1, df2], axis=0, ignore_index=True)  # 纵向堆叠
​
# join 按索引合并
left2 = left.set_index('key')
right2 = right.set_index('key')
joined = left2.join(right2, how='outer')

8.6 重塑与轴向旋转

df = pd.DataFrame({
    '学号': ['001', '001', '002', '002'],
    '学期': ['上学期', '下学期', '上学期', '下学期'],
    '成绩': [85, 90, 78, 88]
})
​
# 把“学期”列值变成列名(长表转宽表)
wide_df = df.pivot(index='学号', columns='学期', values='成绩')
​
# 逆操作:宽表转长表
long_df = wide_df.reset_index().melt(id_vars='学号', var_name='学期', value_name='成绩')
​
# stack / unstack:多层索引间转换
stacked = wide_df.stack()
unstacked = stacked.unstack()

9. 时间序列处理

Pandas 对时间序列的支持堪称一绝,是金融分析、物联网等领域的利器。

9.1 日期解析与生成

# 生成日期范围
dates = pd.date_range(start='2025-01-01', periods=5, freq='D')
​
# 解析字符串为 datetime
raw = pd.Series(['2025-03-15', '2025-04-20'])
dt = pd.to_datetime(raw)
​
# 解析时区信息
dt_tz = pd.to_datetime('2025-05-01 12:00:00').tz_localize('Asia/Shanghai')

9.2 时间索引与切片

df = pd.DataFrame({
    'value': range(5)},
    index=pd.to_datetime(['2025-01-01', '2025-01-03', '2025-01-05', '2025-02-01', '2025-02-15']))
df = df.sort_index()
​
# 按年份、月份切片(自动识别)
print(df['2025-01'])      # 取1月所有数据
print(df['2025-01':'2025-02'])  # 区间切片

9.3 重采样(Resample)

改变时间频率并聚合。

ts = pd.Series(np.random.randn(100),
               index=pd.date_range('2025-01-01', periods=100, freq='D'))
​
# 下采样到月,计算均值
monthly_mean = ts.resample('M').mean()
​
# 上采样到小时并向前填充
hourly = ts.resample('h').ffill()

9.4 移动窗口与移位

# 7日移动平均
rolling_mean = ts.rolling(window=7).mean()
​
# 扩大窗口(从起点到当前)
expanding_sum = ts.expanding().sum()
​
# 向前/后移位(常用来计算差值)
shifted = ts.shift(1)
daily_change = ts - shifted

10. 数据可视化

Pandas 借助 Matplotlib 可以快速出图,非常适合探索性分析。

import matplotlib.pyplot as plt
​
df = pd.DataFrame({
    '季度': ['Q1', 'Q2', 'Q3', 'Q4'],
    '销售额': [100, 120, 115, 130],
    '利润': [20, 25, 22, 28]
}).set_index('季度')
​
# 折线图
df['销售额'].plot(kind='line', title='季度销售额', figsize=(8,4))
plt.show()
​
# 柱状图
df.plot(kind='bar', title='销售与利润对比')
plt.show()
​
# 直方图
df_random = pd.DataFrame({'data': np.random.randn(1000)})
df_random['data'].plot(kind='hist', bins=30, alpha=0.7)
plt.show()

更多定制化需求可结合 Matplotlib 或 Seaborn 实现。

11. 进阶技巧与性能调优

11.1 巧用 category 减少内存

对重复率高的字符串列,转换为 category 类型可大幅节省内存。

df = pd.DataFrame({'city': ['上海','北京','上海','广州']*250000})  # 100万行
print(df.memory_usage(deep=True))
​
df['city'] = df['city'].astype('category')
print(df.memory_usage(deep=True))  # 内存通常能减少70%以上

11.2 eval() 与 query() 加速

对于大型 DataFrame,使用字符串表达式的 eval()query() 可避免多余计算与内存拷贝。

df = pd.DataFrame({'A': [1,2,3], 'B': [10,20,30]})
# 普通方法:df['C'] = df['A'] + df['B']
df.eval('C = A + B', inplace=True)
​
# 与 query 结合过滤
result = df.query('C > 15')

11.3 避免 SettingWithCopyWarning

当你对筛选出的子集进行赋值时,Pandas 经常发出 SettingWithCopyWarning,根本原因在于视图 vs 拷贝的不确定性。

错误示范

subset = df[df['A'] > 0]
subset['B'] = 0   # Warning!

正确姿势:使用 .loc 在原 DataFrame 上直接赋值。

df.loc[df['A'] > 0, 'B'] = 0

11.4 分块读取超大文件

文件内存放不下时,可采用 chunksize 逐块处理。

chunk_list = []
for chunk in pd.read_csv('large_file.csv', chunksize=50000):
    # 每块做预处理,例如过滤、聚合
    processed = chunk[chunk['value'] > 0]
    chunk_list.append(processed.groupby('type').sum())
​
final_result = pd.concat(chunk_list).groupby('type').sum()

12. 总结与学习路径

Pandas 是一座功能宝库,本文覆盖了日常数据分析工作中 90% 以上的高频操作,但你还可以继续深入:

  • 官方文档pandas.pydata.org 是终极参考

  • 《利用 Python 进行数据分析》:Pandas 作者 Wes McKinney 所著,必读经典

  • 多动手:建议拿 Kaggle 上的数据集(如 Titanic、House Prices)从头到尾实践一遍

掌握了这些,你就获得了用 Python 驯服数据的钢筋骨架。剩下的就是不断练习,让肌肉记忆替你完成那些曾经需要查文档的操作。


如果这篇文章对你有帮助,欢迎点赞、收藏、关注,你的支持是创作最大的动力!如有任何疑问或想了解的主题,也欢迎在评论区留言交流。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐