Pandas全方位指南:从入门到精通的数据分析神器(附海量实例)
引言
Python 凭借其简洁的语法和强大的生态,已成为数据科学领域的首选语言。而在数据处理与分析这个核心环节中,Pandas 几乎是你无法绕过的存在。无论你面对的是琐碎的表格整理、混乱的缺失值清洗,还是复杂的多源数据融合,Pandas 都能以优雅且高效的方式完成任务。
本文将为你提供一份全方位无死角的 Pandas 学习指南。从核心数据结构到高级技巧,每一节都配有即刻可运行的代码示例与输出,力求让你既能看懂,又能真正用起来。无论你是零基础小白,还是希望系统梳理知识体系的开发者,这篇长文都将成为你收藏夹里的案头参考。
目录
11.3 避免 SettingWithCopyWarning
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 的两大核心是 Series 和 DataFrame,所有操作都围绕它们展开。
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 驯服数据的钢筋骨架。剩下的就是不断练习,让肌肉记忆替你完成那些曾经需要查文档的操作。
如果这篇文章对你有帮助,欢迎点赞、收藏、关注,你的支持是创作最大的动力!如有任何疑问或想了解的主题,也欢迎在评论区留言交流。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)