Pandas 教程
Pandas 是 Python 最核心的数据分析库,提供了高性能、易用的数据结构和数据分析工具。它建立在 NumPy 之上,名字来源于 Panel Data(面板数据)。
Pandas 能做什么
| 能力 | 说明 |
|---|---|
| 数据读写 | CSV / Excel / JSON / SQL / Parquet 等格式 |
| 数据清洗 | 缺失值、重复值、异常值处理 |
| 数据变换 | 筛选、排序、分组、合并、重塑 |
| 时间序列 | 日期解析、重采样、滚动窗口 |
| 统计分析 | 描述统计、相关性、聚合 |
import pandas as pd
df = pd.read_csv('data.csv') # 读取数据
print(df.head()) # 查看前 5 行
print(df.info()) # 数据概览pip install pandas,官方文档:https://pandas.pydata.org。pandas 简介
pandas 由 Wes McKinney 于 2008 年开发,是 Python 数据科学生态(NumPy → Pandas → Matplotlib → Scikit-learn)中的数据操作层。
两大核心数据结构
| 结构 | 维度 | 说明 |
|---|---|---|
| Series | 一维 | 带标签的数组,类似带索引的列表/字典 |
| DataFrame | 二维 | 带行、列标签的表格,类似 Excel 工作表 |
import pandas as pd
# Series:一维带标签
s = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
# DataFrame:二维表格
df = pd.DataFrame({
'姓名': ['张三', '李四'],
'年龄': [25, 30]
})Pandas 安装
安装 Pandas 非常简单,推荐使用 pip:
# 安装最新版
pip install pandas
# 安装指定版本
pip install pandas==2.2.2
# 使用 Anaconda 环境
conda install pandas# 验证安装
import pandas as pd
print(pd.__version__) # 如 2.2.2Pandas Series
Series 是 Pandas 的一维带标签数组,索引默认从 0 开始:
import pandas as pd
# 从列表创建
s = pd.Series([10, 20, 30])
# 0 10
# 1 20
# 2 30
# 自定义索引
s2 = pd.Series([10, 20, 30], index=['a', 'b', 'c'])
# 从字典创建(键自动成为索引)
s3 = pd.Series({'a': 1, 'b': 2})
# 访问与运算
print(s2['a']) # 10
print(s2 + 1) # 广播运算
print(s2.mean()) # 20.0Pandas DataFrame
DataFrame 是 Pandas 的二维表格数据结构,由行索引(index)和列(columns)组成:
import pandas as pd
df = pd.DataFrame({
'姓名': ['张三', '李四', '王五'],
'年龄': [25, 30, 28],
'城市': ['北京', '上海', '广州']
}, index=['u1', 'u2', 'u3'])
print(df.shape) # (3, 3) 行×列
print(df.columns) # Index(['姓名','年龄','城市'])
print(df.index) # Index(['u1','u2','u3'])
# 常用查看方法
print(df.head(2)) # 前 2 行
print(df.describe()) # 数值列统计概要Pandas 数据读写
Pandas 支持多种数据源的读写,统一接口为 pd.read_xxx() 与 df.to_xxx():
| 格式 | 读取 | 写出 |
|---|---|---|
| CSV | read_csv | to_csv |
| Excel | read_excel | to_excel |
| JSON | read_json | to_json |
| SQL | read_sql | to_sql |
| HTML | read_html | to_html |
| Parquet | read_parquet | to_parquet |
import pandas as pd
df = pd.read_csv('data.csv')
df.to_excel('output.xlsx', index=False)to_excel 需要额外安装 openpyxl:pip install openpyxl。Pandas CSV
CSV(逗号分隔值)是最常见的数据交换格式,read_csv 参数丰富:
import pandas as pd
# 基础读取
df = pd.read_csv('sales.csv')
# 常用参数
df = pd.read_csv(
'sales.csv',
encoding='utf-8', # 编码(中文数据常见 gbk)
sep=',', # 分隔符
header=0, # 第 0 行为列名
index_col=0, # 第 0 列作为行索引
usecols=['date', 'amount'], # 只读指定列
parse_dates=['date'], # 解析为日期
nrows=1000 # 只读前 1000 行
)
# 写出
df.to_csv('out.csv', index=False, encoding='utf-8-sig')utf-8-sig 编码,避免乱码。Pandas Excel
Excel 读写需要 openpyxl 或 xlrd 库:
import pandas as pd
# 读取指定工作表
df = pd.read_excel('book.xlsx', sheet_name='Sheet1')
# 读取所有工作表(返回 dict)
sheets = pd.read_excel('book.xlsx', sheet_name=None)
# 读取指定单元格区域
df = pd.read_excel('book.xlsx', header=0, skiprows=1)
# 写出(可写多个工作表)
with pd.ExcelWriter('out.xlsx') as writer:
df1.to_excel(writer, sheet_name='销售', index=False)
df2.to_excel(writer, sheet_name='用户', index=False)pip install openpyxl(读写 .xlsx)。Pandas JSON
JSON 数据的读取与解析:
import pandas as pd
import json
# 从文件读取
df = pd.read_json('data.json')
# 从字符串读取
df = pd.read_json('{"a": [1, 2], "b": [3, 4]}')
# 嵌套 JSON 需要 json_normalize(新版 pandas.json_normalize)
from pandas import json_normalize
data = [
{"id": 1, "info": {"name": "张三", "city": "北京"}},
{"id": 2, "info": {"name": "李四", "city": "上海"}}
]
df = json_normalize(data)
# 列: id, info.name, info.city
# 写出
df.to_json('out.json', orient='records', force_ascii=False)force_ascii=False 保证中文不被转义为 unicode。Pandas 读取 SQL
读取 SQL 数据库需要 sqlalchemy 与对应驱动(如 pymysql):
import pandas as pd
from sqlalchemy import create_engine
# 连接 MySQL
engine = create_engine('mysql+pymysql://user:pass@localhost:3306/mydb')
# 读取整表
df = pd.read_sql('SELECT * FROM orders', engine)
# 读取并指定列
df = pd.read_sql('SELECT id, amount, created_at FROM orders WHERE amount > 100',
engine, parse_dates=['created_at'])
# 写回数据库
df.to_sql('orders_backup', engine, if_exists='replace', index=False)if_exists 可选 replace(删表重建)/ append(追加)。Pandas 读取 HTML
read_html 可以直接解析网页中的表格:
import pandas as pd
# 读取网页中所有表格(返回列表)
tables = pd.read_html('https://example.com/table.html')
# 取第一个表格
df = tables[0]
# 从 HTML 字符串解析
df = pd.read_html('<table><tr><td>1</td></tr></table>')[0]read_html 依赖 lxml 或 html5lib 解析器,需先安装。Pandas Parquet / Feather
Parquet 是列式存储格式,体积小、读取快;Feather 是跨语言的高速格式,均适合大数据量场景:
import pandas as pd
# Parquet(推荐,压缩率高)
df.to_parquet('data.parquet', engine='pyarrow')
df = pd.read_parquet('data.parquet')
# Feather(读写最快)
df.to_feather('data.feather')
df = pd.read_feather('data.feather')pip install pyarrow。大数据量下 Parquet 读写性能远超 CSV。Pandas 数据导出
数据导出常用方法与参数:
import pandas as pd
# CSV
df.to_csv('out.csv', index=False, encoding='utf-8-sig')
# Excel
df.to_excel('out.xlsx', index=False, sheet_name='数据')
# JSON
df.to_json('out.json', orient='records', force_ascii=False)
# SQL
df.to_sql('table', engine, if_exists='append', index=False)
# 压缩导出(CSV 自动 gzip)
df.to_csv('out.csv.gz', compression='gzip')index=False 可避免把行索引写进文件,是多数场景的推荐配置。Pandas 数据清洗
数据清洗是数据分析中最耗时的一步,Pandas 提供了系统化的工具:
import pandas as pd
df = pd.read_csv('dirty.csv')
# 1. 查看缺失
print(df.isnull().sum())
# 2. 删除缺失行/列
df.dropna() # 删含缺失的行
df.dropna(axis=1) # 删含缺失的列
df.dropna(subset=['age']) # 仅当指定列为空时删除
# 3. 填充缺失
df['age'].fillna(df['age'].median(), inplace=True)
df['city'].fillna('未知', inplace=True)
# 4. 处理重复
df.drop_duplicates(inplace=True)
# 5. 类型转换
df['amount'] = df['amount'].astype(float)
# 6. 处理异常值(如年龄 > 120 视为缺失)
df.loc[df['age'] > 120, 'age'] = Noneinplace=True 会直接修改原对象;新版 Pandas 更推荐 df = df.assign(...) 赋值式写法。Pandas 常用函数
Pandas 常用函数一览:
import pandas as pd
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
# 概览
df.head() / df.tail() # 首/尾几行
df.info() # 列类型与缺失
df.describe() # 数值统计概要
df.shape / df.dtypes # 形状 / 类型
df.nunique() # 每列唯一值数量
df.value_counts('city') # 分类计数
df.sort_values('a', ascending=False) # 排序
df.groupby('city')['amount'].sum() # 分组聚合
df.merge(df2, on='id') # 合并
df.pivot_table(index='city', values='amount', aggfunc='mean') # 透视表df.列名 与 df[列名] 等价,推荐用后一种避免歧义。Pandas 相关性分析
相关性分析用于衡量变量之间的线性相关程度:
import pandas as pd
df = pd.read_csv('data.csv')
# 相关系数矩阵(默认 Pearson)
corr = df.corr()
print(corr)
# 指定方法
df.corr(method='pearson') # 线性相关
df.corr(method='spearman') # 秩相关(非线性)
df.corr(method='kendall') # 肯德尔相关
# 某一列与其他列的相关性
df['price'].corr(df['area'])
# 可视化热力图
import seaborn as sns
sns.heatmap(corr, annot=True)Pandas 数据排序与聚合
排序与聚合是数据分析最常用的两大操作:
import pandas as pd
# 排序
df.sort_values('age', ascending=False) # 单列
df.sort_values(['city', 'age'], ascending=[True, False]) # 多列
# 聚合(groupby + agg)
result = df.groupby('city').agg({
'amount': ['sum', 'mean', 'count', 'max'],
'age': 'mean'
})
print(result)
# 命名聚合(Pandas 0.25+)
result = df.groupby('city').agg(
总金额=('amount', 'sum'),
平均金额=('amount', 'mean'),
人数=('user_id', 'nunique')
)agg 接受字典或列表,可同时对不同列应用不同聚合函数。Pandas 数据可视化
Pandas 内置 plot 方法快速出图(基于 Matplotlib):
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('sales.csv')
# 折线图
df.plot(x='date', y='amount', kind='line')
# 柱状图
df.groupby('city')['amount'].sum().plot(kind='bar')
# 饼图
df['category'].value_counts().plot(kind='pie', autopct='%.1f%%')
# 直方图
df['age'].plot(kind='hist', bins=20)
# 箱线图
df[['a', 'b']].plot(kind='box')
plt.show()seaborn 可获得更美观的统计图,两库可无缝混用。Pandas 高级功能
Pandas 高级功能包括透视表、交叉表、管道等:
import pandas as pd
# 透视表:类似 Excel 数据透视
pv = df.pivot_table(
index='city', # 行
columns='category', # 列
values='amount', # 值
aggfunc='sum', # 聚合方式
fill_value=0 # 缺失填充
)
# 交叉表:分类变量的频次
ct = pd.crosstab(df['city'], df['category'])
# 管道:串联多个处理步骤
def add_flag(d): return d.assign(flag=d['amount'] > 100)
def scale(d): return d.assign(amount2=d['amount'] * 1.1)
result = (df.pipe(add_flag).pipe(scale))Pandas 性能优化
大数据量下的性能优化技巧:
import pandas as pd
# 1. 只读需要的列
df = pd.read_csv('big.csv', usecols=['id', 'amount'])
# 2. 指定数据类型(大幅减少内存)
df = pd.read_csv('big.csv', dtype={'id': 'int32', 'is_vip': 'bool'})
# 3. 用 category 压缩低基数分类列
df['city'] = df['city'].astype('category')
# 4. 向量化操作代替循环(避免 iterrows)
df['new'] = df['a'] * 2 + df['b'] # ✅ 向量化
# for i, row in df.iterrows(): ... # ❌ 极慢
# 5. 使用分块读取大文件
chunks = pd.read_csv('big.csv', chunksize=100000)
result = pd.concat([c.groupby('city').size() for c in chunks])
# 6. 用 memory_usage 检查内存
print(df.memory_usage(deep=True))Pandas 股票数据分析
用 Pandas 做股票数据分析的完整小案例(数据可用 akshare / yfinance 获取):
import pandas as pd
# 假设已获取股票日线数据
df = pd.DataFrame({
'date': pd.date_range('2026-01-01', periods=20, freq='D'),
'close': [10 + i * 0.1 for i in range(20)]
})
df.set_index('date', inplace=True)
# 技术指标:5 日均线
df['ma5'] = df['close'].rolling(5).mean()
# 日收益率
df['ret'] = df['close'].pct_change()
# 累计收益率
df['cum_ret'] = (1 + df['ret']).cumprod()
# 波动率(滚动标准差)
df['vol'] = df['ret'].rolling(5).std()
# 最高/最低
print(df[['close', 'ma5']].describe())akshare:pip install akshare,一行获取 A 股行情。Pandas Index 详解
Index(索引)是 Pandas 数据结构的核心:
import pandas as pd
df = pd.DataFrame({'a': [1, 2, 3]}, index=['x', 'y', 'z'])
# 索引属性
print(df.index) # Index(['x','y','z'])
print(df.index.name) # 索引名
# 重置 / 设置索引
df.reset_index() # 索引变回普通列
df.set_index('a') # 用指定列作索引
# 按索引筛选
df.loc['x'] # 按标签取行
df.iloc[0] # 按位置取行
# 索引排序 / 唯一性
df.sort_index()
df.index.is_uniqueloc 用标签、iloc 用位置,两者不要混淆。Pandas 多层索引
多层索引(MultiIndex)支持多维数据的层次化组织:
import pandas as pd
# 创建多层索引
df = pd.DataFrame(
{'amount': [1, 2, 3, 4]},
index=pd.MultiIndex.from_tuples([
('北京', '2026-01'), ('北京', '2026-02'),
('上海', '2026-01'), ('上海', '2026-02')
], names=['city', 'month'])
)
# 按第一层取数据
df.loc['北京']
# 按多级切片
df.loc[('北京', '2026-01')]
# 交换层级 / 堆叠
df.swaplevel() # 交换层顺序
df.unstack() # 最内层索引转列
df.stack() # 列转索引Pandas 数据类型
Pandas 数据类型(dtype)与转换:
import pandas as pd
# 常见 dtype
# int64 / float64 / object / bool
# datetime64[ns] / timedelta64[ns] / category
df = pd.DataFrame({
'age': ['25', '30', '28'], # object(文本数字)
'price': [9.9, 19.9, 29.9],
'date': ['2026-01-01'] * 3
})
# 类型转换
df['age'] = df['age'].astype(int) # str -> int
df['date'] = pd.to_datetime(df['date']) # str -> datetime
df['price'] = df['price'].round(2) # 保留小数
# 查看类型
print(df.dtypes)Pandas 类别类型
category(类别)类型适合取值有限的列(性别、城市、状态等),可节省内存并加速分组:
import pandas as pd
df = pd.DataFrame({'city': ['北京', '上海', '北京', '广州']})
# 转为 category
df['city'] = df['city'].astype('category')
print(df['city'].cat.categories) # ['北京','上海','广州']
# 有序类别(重要程度)
df['level'] = pd.Categorical(
['低', '高', '中', '高'],
categories=['低', '中', '高'], ordered=True
)
# 类别统计
df['city'].value_counts()groupby 时性能显著优于 object 类型。Pandas 数据选取
数据选取是 Pandas 最常用的操作,掌握 loc/iloc/at/iat 是关键:
import pandas as pd
df = pd.DataFrame({
'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]
}, index=['r1', 'r2', 'r3'])
# 列选取
df['a'] # 单列(Series)
df[['a', 'b']] # 多列(DataFrame)
# 行选取
df.loc['r1'] # 标签取行
df.iloc[0] # 位置取行
df.loc[['r1', 'r2']] # 多行
# 行列同时选
df.loc['r1', 'a'] # 单值
df.loc[['r1','r2'], ['a','b']] # 子集
df.iloc[0:2, 0:2] # 位置切片
# at/iat(更快,单值)
df.at['r1', 'a']
df.iat[0, 0]df[a] 返回 Series,df[[a]] 返回 DataFrame,二者有区别。Pandas 过滤与条件查询
过滤与条件查询:
import pandas as pd
df = pd.DataFrame({
'city': ['北京','上海','北京','广州'],
'amount': [100, 200, 300, 400],
'age': [25, 30, 28, 35]
})
# 单条件
df[df['amount'] > 150]
# 多条件(& 与,| 或,~ 非,注意加括号)
df[(df['city'] == '北京') & (df['amount'] > 150)]
df[(df['city'] == '北京') | (df['age'] > 30)]
# isin 过滤
df[df['city'].isin(['北京', '上海'])]
# query 表达式(更简洁)
df.query('amount > 150 and city == "北京"')
# between 范围
df[df['age'].between(26, 32)]&、逻辑或用 |,不能用 Python 的 and/or。Pandas 缺失值处理
缺失值处理是数据清洗的核心:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'a': [1, np.nan, 3],
'b': [np.nan, 5, 6]
})
# 检测
df.isnull() # 逐元素判断
df.isnull().sum() # 每列缺失数
df.notnull()
# 删除
df.dropna() # 含缺失即删行
df.dropna(how='all') # 全空才删
df.dropna(thresh=2) # 至少 2 个非空才保留
# 填充
df.fillna(0) # 常数
df['a'].fillna(df['a'].mean()) # 均值
df.fillna(method='ffill') # 前向填充
df.fillna(method='bfill') # 后向填充
df.interpolate() # 线性插值Pandas 重复数据处理
重复数据处理:
import pandas as pd
df = pd.DataFrame({
'id': [1, 2, 2, 3, 3, 3],
'name': ['a', 'b', 'b', 'c', 'c', 'c']
})
# 检测重复
df.duplicated() # 整行重复
df.duplicated(subset=['id']) # 指定列重复
# 删除重复
df.drop_duplicates()
df.drop_duplicates(subset=['id'])
df.drop_duplicates(keep='last') # 保留最后一条
df.drop_duplicates(keep=False) # 全部删除
# 统计
df.duplicated().sum()keep 参数控制保留哪一条:first(默认)/ last / False(全删)。Pandas 字符串操作
字符串操作通过 str 访问器:
import pandas as pd
df = pd.DataFrame({'name': [' 张三 ', 'Li Si', '王五'], 'phone': ['138-0000', '139-1111', '']})
# 清洗
df['name'] = df['name'].str.strip() # 去空格
df['name'] = df['name'].str.upper() # 转大写
# 判断
df['name'].str.contains('张') # 包含
df['name'].str.startswith('L') # 前缀
df['phone'].str.replace('-', '', regex=False) # 替换
# 拆分与拼接
df[['a', 'b']] = df['phone'].str.split('-', expand=True)
df['full'] = df['a'] + '-' + df['b']
# 提取
df['phone'].str.extract(r'(\d{3})') # 正则提取str 操作不会报错,返回 NaN;正则表达式需注意转义。Pandas 日期与时间
日期与时间处理:
import pandas as pd
# 解析日期
s = pd.to_datetime(['2026-01-01', '2026-02-01', '20260103'])
print(s) # DatetimeIndex
# 生成日期范围
dates = pd.date_range('2026-01-01', periods=10, freq='D')
dates = pd.date_range('2026-01-01', '2026-12-31', freq='M') # 月末
# 提取日期成分
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
df['weekday'] = df['date'].dt.dayofweek # 0=周一
df['quarter'] = df['date'].dt.quarter
# 日期运算
df['date'] + pd.Timedelta(days=7) # 加 7 天
df['date'].diff() # 间隔pd.to_datetime 会自动识别常见格式。Pandas 时间序列分析
时间序列分析:
import pandas as pd
# 构造时间序列(设置日期为索引)
ts = pd.Series(
[10, 12, 11, 15, 14, 18],
index=pd.date_range('2026-01-01', periods=6, freq='D')
)
# 重采样(resample):聚合到新频率
ts.resample('W').sum() # 按周汇总
ts.resample('M').mean() # 按月平均
# 滚动窗口
ts.rolling(3).mean() # 3 日移动平均
ts.rolling(3).std() # 滚动标准差
# 移动平均绘图
ts.rolling(3).mean().plot()
# 滞后/差分(平稳化)
ts.diff() # 一阶差分
ts.shift(1) # 整体后移 1 期set_index 并排序,再使用 resample/rolling。Pandas apply / map / applymap
apply / map / applymap 三个函数的区别:
import pandas as pd
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
# map:Series 元素级映射(可用函数或字典)
df['a'].map(lambda x: x * 10)
df['a'].map({1: '一', 2: '二', 3: '三'})
# apply:DataFrame 按行/列应用函数(axis=0 列,1 行)
df.apply(lambda col: col.sum()) # 每列求和
df.apply(lambda row: row['a'] + row['b'], axis=1) # 每行计算
# applymap:所有元素级操作(DataFrame)
df.applymap(lambda x: x * 2)
# 新版:map(DataFrame 级)
df.map(lambda x: x * 2)Pandas 数据合并
数据合并(merge,类似 SQL JOIN):
import pandas as pd
users = pd.DataFrame({'id': [1, 2, 3], 'name': ['a', 'b', 'c']})
orders = pd.DataFrame({'id': [1, 2, 2], 'amount': [100, 200, 300]})
# 内连接(默认)
pd.merge(users, orders, on='id')
# 左连接(保留左表全部)
pd.merge(users, orders, on='id', how='left')
# 右连接 / 外连接
pd.merge(users, orders, on='id', how='right')
pd.merge(users, orders, on='id', how='outer')
# 不同列名连接
pd.merge(users, orders, left_on='id', right_on='user_id')
# 多键连接
pd.merge(a, b, on=['key1', 'key2'])Pandas 数据拼接
数据拼接(concat,按方向堆叠):
import pandas as pd
df1 = pd.DataFrame({'a': [1, 2], 'b': [3, 4]})
df2 = pd.DataFrame({'a': [5, 6], 'b': [7, 8]})
# 纵向拼接(追加行,默认)
pd.concat([df1, df2], ignore_index=True)
# 横向拼接(追加列)
df3 = pd.DataFrame({'c': [9, 9]})
pd.concat([df1, df3], axis=1)
# 带来源标记
pd.concat([df1, df2], keys=['第一组', '第二组'])
# 拼接后重置索引
pd.concat([df1, df2]).reset_index(drop=True)ignore_index=True 可避免拼接后索引重复。Pandas 数据重塑
数据重塑(pivot / melt / stack / unstack):
import pandas as pd
df = pd.DataFrame({
'city': ['北京', '北京', '上海', '上海'],
'month': [1, 2, 1, 2],
'amount': [100, 110, 200, 210]
})
# pivot:长表转宽表
pv = df.pivot(index='city', columns='month', values='amount')
# melt:宽表转长表(逆透视)
wide = pd.DataFrame({
'city': ['北京', '上海'],
'Q1': [100, 200], 'Q2': [110, 210]
})
long = wide.melt(id_vars='city', var_name='quarter', value_name='amount')
# stack / unstack:索引与列互转
pv.stack() # 列转索引(长表)
pv.unstack() # 索引转列(宽表)Pandas 分组操作
分组操作(groupby)是聚合分析的核心:
import pandas as pd
df = pd.DataFrame({
'city': ['北京', '北京', '上海', '上海', '广州'],
'cat': ['A', 'B', 'A', 'B', 'A'],
'amount': [100, 200, 150, 250, 300]
})
# 单列分组
df.groupby('city')['amount'].sum()
# 多列分组
df.groupby(['city', 'cat'])['amount'].sum()
# 多聚合
df.groupby('city')['amount'].agg(['sum', 'mean', 'count'])
# 分组后遍历
for name, group in df.groupby('city'):
print(name, group.shape)
# transform:保持原行数
df['city_sum'] = df.groupby('city')['amount'].transform('sum')
# filter:过滤组
df.groupby('city').filter(lambda g: g['amount'].sum() > 300)Pandas 窗口函数
窗口函数(rolling / expanding)用于滑动窗口计算:
import pandas as pd
s = pd.Series([1, 2, 3, 4, 5, 6])
# rolling:定长滚动窗口
s.rolling(3).mean() # 每 3 个一组求均值
s.rolling(3).sum()
s.rolling(3).max()
# expanding:累计窗口(从第一个元素到当前)
s.expanding().sum() # 累计和
s.expanding().mean() # 累计均值
# 窗口中心化 / 最小样本数
s.rolling(3, center=True).mean()
s.rolling(3, min_periods=1).mean()
# 时间窗口(索引为日期)
ts.rolling('7D').mean() # 7 天滚动均值Pandas Input/Output API
Pandas 的 I/O API 统一管理所有读写方法:
| 读取 | 写出 | 格式 |
|---|---|---|
| read_csv | to_csv | CSV/文本 |
| read_excel | to_excel | Excel |
| read_json | to_json | JSON |
| read_html | to_html | HTML 表格 |
| read_sql / read_sql_query | to_sql | SQL 数据库 |
| read_parquet | to_parquet | Parquet |
| read_feather | to_feather | Feather |
| read_pickle | to_pickle | Pickle |
| read_clipboard | to_clipboard | 剪贴板 |
import pandas as pd
# 剪贴板快速读写(Excel 复制 → DataFrame)
df = pd.read_clipboard()
df.to_clipboard(index=False)read_clipboard 非常适合临时把 Excel/网页表格粘进来分析。Pandas Series API 手册
Series 常用 API 速查:
import pandas as pd
s = pd.Series([3, 1, 2, 2, 3])
s.values # 底层数组
s.index # 索引
s.dtype # 类型
s.shape # 形状
s.size # 元素数
s.head() / s.tail()
s.describe() # 统计概要
s.sum() / s.mean() / s.median() / s.std()
s.min() / s.max() / s.quantile(0.5)
s.unique() # 去重
s.value_counts() # 频次
s.sort_values() / s.sort_index()
s.isna() / s.notna()
s.fillna(0) / s.dropna()
s.map(fn) # 元素级映射
s.apply(fn) # 函数应用
s.rolling(3).mean()Pandas DataFrame API 手册
DataFrame 常用 API 速查:
import pandas as pd
df = pd.DataFrame({'a': [1, 2], 'b': [3, 4]})
df.shape / df.columns / df.index / df.dtypes
df.head() / df.tail() / df.info()
df.describe() # 数值统计
df.sum() / df.mean() # 列级聚合(axis=0)
df.mean(axis=1) # 行级聚合
df.sort_values('a')
df.groupby('a').sum()
df.merge(df2, on='k') / pd.concat([df1, df2])
df.pivot_table(index='a', values='b', aggfunc='mean')
df.drop(columns=['b']) # 删列
df.rename(columns={'a': 'A'})
df.set_index('a') / df.reset_index()
df.apply(fn, axis=1)
df.corr() / df.cov()Pandas 数组
Pandas 中的数组:底层基于 NumPy 数组,也支持 pandas 扩展数组:
import pandas as pd
import numpy as np
# 从 NumPy 数组创建
arr = np.array([1, 2, 3])
s = pd.Series(arr)
df = pd.DataFrame(arr.reshape(1, 3))
# 底层数组访问
s.values # numpy.ndarray
df.to_numpy() # 推荐,转 numpy
# pandas 扩展数组类型
s = pd.array([1, 2, None], dtype='Int64') # 可空整型
s = pd.array(['a', None], dtype='string') # 可空字符串
# 与 NumPy 互转
df.to_numpy().sum()to_numpy() 比 values 更稳定(支持扩展类型)。Pandas Index 对象
Index 对象深入:
import pandas as pd
idx = pd.Index(['b', 'a', 'c'])
idx.name # 名称
idx.dtype # 类型
idx.is_unique # 是否唯一
idx.is_monotonic_increasing # 是否递增
idx.tolist() # 转列表
idx.sort_values() # 排序
# 创建不同索引
pd.RangeIndex(0, 10) # 范围索引
pd.Index([1, 2, 3], name='id')
pd.MultiIndex.from_product([['A','B'], [1,2]]) # 笛卡尔积
# 索引运算
idx1.intersection(idx2) # 交集
idx1.union(idx2) # 并集
idx1.difference(idx2) # 差集Pandas DateOffset 对象
DateOffset 对象用于日期偏移计算(比 Timedelta 更贴合日历语义):
import pandas as pd
now = pd.Timestamp('2026-01-31')
# 日历偏移:月末 + 1 个月 = 2 月末(自动处理天数)
now + pd.DateOffset(months=1) # 2026-02-28
# 业务日
now + pd.offsets.BDay(1) # 下一个工作日
now + pd.offsets.Week(2) # 加 2 周
now + pd.offsets.MonthEnd() # 当月月末
# 生成频率
pd.date_range('2026-01-01', periods=4, freq='W-MON') # 每周一
pd.date_range('2026-01-01', periods=4, freq='Q') # 每季末DateOffset(months=1) 自动处理大小月;而 Timedelta(days=30) 固定 30 天,语义不同。Pandas 测验
本章提供一组 Pandas 自测题,检验掌握程度:
# 1. 如何读取 CSV 前 100 行?
df = pd.read_csv('x.csv', nrows=100)
# 2. 如何查看缺失值数量?
df.isnull().sum()
# 3. 如何按城市分组求金额均值?
df.groupby('city')['amount'].mean()
# 4. 如何删除重复行?
df.drop_duplicates()
# 5. 如何把列转为日期类型?
df['date'] = pd.to_datetime(df['date'])
# 6. 如何合并两个表?
pd.merge(a, b, on='id')
# 7. 如何计算 3 日移动平均?
df['close'].rolling(3).mean()
# 8. 如何长表转宽表?
df.pivot(index='city', columns='month', values='amount')Pandas 描述性统计
描述性统计:
import pandas as pd
df = pd.DataFrame({'a': [1, 2, 3, 4, 100], 'b': [5, 6, 7, 8, 9]})
# 核心统计
df.describe() # count/mean/std/min/25%/50%/75%/max
df.describe(percentiles=[.1, .9]) # 自定义分位
# 常用统计量
df.mean() / df.median() / df.mode() # 均值/中位数/众数
df.std() / df.var() # 标准差/方差
df.min() / df.max() / df.quantile(.25)
df.skew() # 偏度
df.kurt() # 峰度
# 分组统计
df.groupby('b')['a'].agg(['mean', 'std', 'count'])
# 汇总
df.agg(['sum', 'mean', 'max'])describe() 是快速了解数据分布的第一步,配合 plot(kind="hist") 更直观。Pandas 抽样与随机数据
抽样与随机数据:
import pandas as pd
import numpy as np
# 生成随机数据框
df = pd.DataFrame({
'a': np.random.randn(100),
'b': np.random.randint(0, 10, 100)
})
# 随机抽样
df.sample(10) # 抽 10 行
df.sample(frac=0.2) # 抽 20%
df.sample(10, random_state=42) # 固定随机种子(可复现)
# 按权重抽样
df.sample(10, weights=df['a'].abs())
# 打乱行序
df.sample(frac=1.0).reset_index(drop=True)
# 设置随机种子
np.random.seed(42)
df = pd.DataFrame(np.random.randn(5, 3))random_state 让抽样结果可复现,实验分析必备。Pandas 数据分箱
数据分箱(binning)把连续变量离散化:
import pandas as pd
df = pd.DataFrame({'age': [18, 25, 33, 45, 60, 70]})
# 等宽分箱
bins = [0, 18, 35, 55, 100]
labels = ['未成年', '青年', '中年', '老年']
df['age_group'] = pd.cut(df['age'], bins=bins, labels=labels)
# 等频分箱(按分位数)
df['age_group'] = pd.qcut(df['age'], q=4, labels=['Q1','Q2','Q3','Q4'])
# 查看分箱结果
df['age_group'].value_counts()
# 自定义断点
pd.cut(df['age'], bins=3)cut 按值等宽,qcut 按频数等分;建模前常用分箱处理年龄、收入等字段。Pandas 处理大文件
处理大文件的技巧:
import pandas as pd
# 1. 分块读取(chunksize 返回迭代器)
chunks = pd.read_csv('big.csv', chunksize=100000)
total = 0
for chunk in chunks:
total += chunk['amount'].sum()
print(total)
# 2. 只读需要的列
df = pd.read_csv('big.csv', usecols=['id', 'amount'])
# 3. 优化类型
df = pd.read_csv('big.csv',
dtype={'id': 'int32'},
parse_dates=['date'])
# 4. 用 SQL 预过滤
# pandas.read_sql('SELECT * FROM t WHERE date > ...')
# 5. 并行处理(joblib)
from joblib import Parallel, delayed
parts = Parallel(n_jobs=4)(
delayed(pd.read_csv)(f'part_{i}.csv') for i in range(4)
)
df = pd.concat(parts)Pandas 与 NumPy 结合
Pandas 与 NumPy 的无缝协作:
import pandas as pd
import numpy as np
# NumPy 数组 -> Pandas
arr = np.array([[1, 2], [3, 4]])
df = pd.DataFrame(arr, columns=['a', 'b'])
# Pandas -> NumPy
matrix = df.to_numpy()
matrix2 = df.values # 旧式写法
# 通用函数(ufunc)直接应用
df['c'] = np.sqrt(df['a'])
df['d'] = np.where(df['a'] > 1, '高', '低')
# 广播运算
df + np.array([10, 20]) # 逐行加
# 随机
np.random.seed(0)
df = pd.DataFrame(np.random.randn(100, 3), columns=['x','y','z'])Pandas 可视化
Pandas 可视化进阶:
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({
'date': pd.date_range('2026-01-01', periods=30, freq='D'),
'sales': range(30)
})
# 多子图
fig, axes = plt.subplots(2, 2, figsize=(10, 6))
df.plot(x='date', y='sales', ax=axes[0,0], title='折线')
df['sales'].plot(kind='bar', ax=axes[0,1], title='柱状')
df['sales'].plot(kind='hist', bins=10, ax=axes[1,0], title='直方图')
df['sales'].plot(kind='area', ax=axes[1,1], title='面积')
# 样式
df.plot(style='--', color='red', linewidth=2, grid=True)
# 保存图片
plt.savefig('chart.png', dpi=150, bbox_inches='tight')
plt.show()plt.rcParams["font.sans-serif"]=["SimHei"]。Pandas 电商数据
电商数据分析案例:
import pandas as pd
# 模拟电商订单数据
df = pd.DataFrame({
'order_id': range(1, 101),
'city': ['北京']*30 + ['上海']*40 + ['广州']*30,
'amount': [100, 250, 80, 320, 150, 99] * 16 + [200, 88, 120, 60],
'category': ['数码','服饰','食品','数码','服饰','食品'] * 16 + ['数码']*4,
'date': pd.date_range('2026-01-01', periods=100, freq='D')
})
# 各城市销售额
df.groupby('city')['amount'].sum().sort_values(ascending=False)
# 各类别销量占比
df['category'].value_counts(normalize=True) * 100
# 日均销售额
df.set_index('date')['amount'].resample('D').sum().mean()
# 客单价(每单均值)
df['amount'].mean()
# 复购分析(同一 city 下订单数)
df.groupby('city')['order_id'].count()Pandas 用户行为
用户行为分析案例:
import pandas as pd
# 模拟用户行为日志
df = pd.DataFrame({
'user_id': [1, 1, 1, 2, 2, 3],
'action': ['view', 'cart', 'buy', 'view', 'buy', 'view'],
'ts': pd.date_range('2026-01-01 10:00', periods=6, freq='30min')
})
# 行为漏斗
df['action'].value_counts(normalize=True) * 100
# 用户行为序列(按时间排序)
df.sort_values(['user_id', 'ts']).groupby('user_id')['action'].apply(list)
# 活跃用户数(每日)
df.groupby(df['ts'].dt.date)['user_id'].nunique()
# 转化率:buy 行为用户占比
buyers = df[df['action'] == 'buy']['user_id'].nunique()
all_users = df['user_id'].nunique()
print(f'转化率: {buyers / all_users * 100:.1f}%')Series
本章是 Series 专题:一维数据结构的完整使用场景。
import pandas as pd
# 多种创建方式
pd.Series([1, 2, 3])
pd.Series({'a': 1, 'b': 2})
pd.Series(5, index=['a', 'b', 'c']) # 广播创建
# 索引对齐(Series 运算按索引对齐)
s1 = pd.Series({'a': 1, 'b': 2})
s2 = pd.Series({'b': 10, 'a': 20})
print(s1 + s2) # a: 21, b: 12
# 向量化运算
s = pd.Series([1, 2, 3])
s + 1 / s * 2 / s > 1
# 条件筛选
s[s > 1]
# 统计
s.mean() / s.std() / s.describe()
# 绘图
s.plot(kind='line')DataFrame
本章是 DataFrame 专题:二维表格数据的完整使用场景。
import pandas as pd
# 创建
pd.DataFrame({'a': [1, 2], 'b': [3, 4]})
pd.DataFrame([[1, 2], [3, 4]], columns=['a', 'b'])
# 查看
df.head() / df.info() / df.describe()
# 增删改查
df['c'] = df['a'] + df['b'] # 增列
df.loc[2] = [5, 6, 11] # 增行
df.drop(columns='c') # 删列
df.drop(index=0) # 删行
df.rename(columns={'a': 'A'}) # 改列名
df['a'] = df['a'] * 2 # 改值
# 条件更新
df.loc[df['a'] > 1, 'b'] = 0
# 综合:按城市统计、转置、透视
df.T # 转置
df.pivot_table(index='city', values='amount', aggfunc='sum')