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]
})
✅ 建议
DataFrame 是日常使用最多的对象,掌握它等于掌握了 Pandas 的 80%。

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.2
⚠️ 注意
Python 版本需 ≥3.9;建议在虚拟环境中安装,避免污染全局环境。

Pandas 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.0
✅ 建议
Series 的索引可以是非整数(如字符串),这使得数据访问更语义化。

Pandas 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()) # 数值列统计概要
💡 提示
DataFrame 的每一列本质上都是一个 Series。

Pandas 数据读写

Pandas 支持多种数据源的读写,统一接口为 pd.read_xxx() 与 df.to_xxx():

格式读取写出
CSVread_csvto_csv
Excelread_excelto_excel
JSONread_jsonto_json
SQLread_sqlto_sql
HTMLread_htmlto_html
Parquetread_parquetto_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')
⚠️ 注意
中文写入 Excel 兼容的 CSV 建议用 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'] = None
⚠️ 注意
inplace=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)
✅ 建议
相关系数范围 [-1,1]:接近 1 正相关、接近 -1 负相关、接近 0 无线性关系。

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))
💡 提示
管道(pipe)让数据处理流程化、可复用,适合复杂清洗流程。

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))
✅ 建议
内存优化三板斧:usecols 限列、dtype 定类型、category 压分类列。

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_unique
✅ 建议
loc 用标签、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)]
⚠️ 注意
Pandas 中逻辑与用 &、逻辑或用 |,不能用 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()                      # 线性插值
✅ 建议
时间序列缺失优先用 ffill / 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)
⚠️ 注意
性能排序:向量化运算 > map > apply > 循环。能用向量化就别用 apply。

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'])
💡 提示
how 参数:inner/left/right/outer,与 SQL 语义一致。

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()    # 索引转列(宽表)
💡 提示
melt 常用于把 Excel 风格宽表转为适合分析的长表。

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)
✅ 建议
groupby + agg 是最常用组合;transform 可在分组内做归一化等逐行计算。

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_csvto_csvCSV/文本
read_excelto_excelExcel
read_jsonto_jsonJSON
read_htmlto_htmlHTML 表格
read_sql / read_sql_queryto_sqlSQL 数据库
read_parquetto_parquetParquet
read_featherto_featherFeather
read_pickleto_picklePickle
read_clipboardto_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)
✅ 建议
几个 G 的文件优先 chunksize 流式处理;几十 G 以上建议上数据库或 PySpark。

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 底层就是 NumPy 数组,二者可随时互转,性能无损耗。

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()
💡 提示
这是零售分析的三个核心指标:GMV(总销售额)、客单价、订单量。

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')
💡 提示
Series 的索引对齐机制是 Pandas 强大之处:不同索引的数据也能安全运算。

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')
✅ 建议
DataFrame 是最常用的容器,建议把增删改查、筛选、分组、合并练到肌肉记忆。
第 1 / 55 节