Pandas 是 Python 中最常用的数据分析库。它就像是 Python 中的 Excel,能让我们以表格的形式非常方便地处理和分析数据。
1. Pandas 简介
Pandas 主要有两个核心数据结构:
- Series:类似于一维数组,可以把它看作是 Excel 中的一列。
- DataFrame:类似于二维表格,可以把它看作是 Excel 中的一个 Sheet(工作表)。
2. 基础准备
首先,我们需要导入 Pandas 库。通常我们也会一起导入 NumPy(用于数值计算)。
# 导入库
import pandas as pd
import numpy as np
3. 核心数据结构
3.1 Series (一维序列)
Series 由一组数据(Values)和一组标签(Index)组成。
# 创建 Series, 以日期为索引
dates = pd.date_range('2022-01-01', periods=5, freq='D')
s = pd.Series([1, 3, 5, np.nan, 6], index=dates)
print(s)
3.2 DataFrame (二维数据表)
DataFrame 是最常用的结构。我们可以通过多种方式创建它,比如使用 NumPy 数组或字典。
# 创建测试数据 DataFrame
dates = pd.date_range('2022-01-01', periods=6)
# 创建 6行4列 的随机数
data = np.random.randn(6, 4)
df = pd.DataFrame(data, index=dates, columns=['A', 'B', 'C', 'D'])
# 重命名列名,模拟股票数据
df.columns = ['open', 'high', 'low', 'close']
print(df)
4. 查看与检查数据
拿到数据的第一步通常是“看一看”它长什么样。
# 查看前 5 行 (默认)
df.head()
# 查看后 3 行
df.tail(3)
# 查看索引 (行标签)
df.index
# 输出: DatetimeIndex(['2022-01-01', ...], dtype='datetime64[ns]', freq='D')
# 查看列名
df.columns
# 输出: Index(['open', 'high', 'low', 'close'], dtype='object')
# 查看底层 NumPy 数据
df.values
# 查看每列的数据类型
df.dtypes
统计摘要: describe() 是一个非常强大的函数,可以快速查看数据的 count (计数), mean (均值), std (标准差), min/max 等统计信息。
5. 数据选择 (核心)
Pandas 推荐使用 loc(标签索引)和 iloc(位置索引)来选择数据。
5.1 获取列
# 选择单列,返回 Series
df['close']
# 选择多列,返回 DataFrame
df[['open', 'close']]
5.2 标签选择 (loc)
loc[行标签, 列标签]:通过名字来选。
# 1.获取某一行 (2022-01-01)
df.loc['2022-01-01']
# 2.获取切片范围 (注意:loc 的切片包含两端!)
# 获取 1月1日 到 1月3日 的数据
df.loc['2022-01-01':'2022-01-03']
# 3.同时选择行和列
# 获取 1月1日 的 'open' 和 'close'
df.loc['2022-01-01', ['open', 'close']]
5.3 位置选择 (iloc)
iloc[行号, 列号]:通过数字下标来选(从 0 开始,左闭右开)。
# 1.获取第3行 (下标为2)
df.iloc[2]
# 2.获取前3行,前2列
df.iloc[0:3, 0:2] # 等同于 df.iloc[:3, :2]
# 3.获取特定位置的值 (第0行,第0列)
df.iloc[0, 0]
5.4 布尔索引 (条件筛选)
根据条件筛选出符合要求的数据。
# 1. 筛选收盘价(close)大于 0 的行
df[df.close > 0]
# 2. 整个 DataFrame 进行筛选 (不满足条件的变为 NaN)
df[df > 0]
# 3. 使用 isin 筛选
df2 = df.copy()
df2['tag'] = ['one', 'one', 'two', 'three', 'four', 'three']
# 筛选 tag 是 'one' 或 'two' 的行
df2[df2['tag'].isin(['one', 'two'])]
6. 数据清洗
现实中的数据往往是不干净的,包含缺失值或重复值。
6.1 缺失值处理
在 Pandas 中,np.nan 或 None 代表缺失值。
# 构造一个包含缺失值的 DataFrame
df_nan = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E'])
df_nan.loc[dates[0]:dates[1], 'E'] = 1 # 赋值
# 此时 df_nan 中存在 NaN
# 1. 除去包含缺失值的行
df_nan.dropna(how='any')
# 2. 填充缺失值
df_nan.fillna(value=5)
# 3. 判断是否为缺失值 (返回布尔表)
pd.isnull(df_nan)
6.2 去重
df_dup = pd.DataFrame({'k1': ['one', 'two'] * 3 + ['two'], 'k2': [1, 1, 2, 3, 3, 4, 4]})
# 去除重复行
df_dup.drop_duplicates()
6.3 丢弃数据 (Drop)
# 丢弃行 (按索引)
df.drop('2022-01-01')
# 丢弃列 (按列名, axis=1)
df.drop('open', axis=1)
7. 数据运算与变换
7.1 统计运算
# 平均值 (默认按列)
df.mean()
# 按行求平均
df.mean(1)
# Apply 函数:对数据应用自定义函数
# 例如:计算每日最大值与最小值的差 (振幅)
df.apply(lambda x: x.max() - x.min())
7.2 字符串操作
Pandas 为 Series 提供了 .str 属性,可以方便地处理字符串。
s = pd.Series(['A', 'B', 'C', 'Aaba', 'Baca', np.nan, 'CABA', 'dog', 'cat'])
# 转小写
s.str.lower()
# 判断是否包含 'a'
s.str.contains('a')
7.3 Shift (数据偏移/回溯)
常用于计算环比增长、收益率等。
# 构造 close 价格
s_close = pd.Series([10, 11, 12, 11, 12], index=dates[:5])
# 计算每日收益率: (今天 - 昨天) / 昨天
# shift(1) 表示将数据向下移动 1 位 (即昨天的全部对应到了今天)
daily_returns = s_close / s_close.shift(1) - 1
print(daily_returns)
8. 数据合并
8.1 Concat (连接)
简单的堆叠(上下或左右)。
# 分割数据
df1 = df.iloc[:3]
df2 = df.iloc[3:]
# 上下拼接
pd.concat([df1, df2])
8.2 Merge (数据库风格合并)
类似于 SQL 中的 JOIN。
left = pd.DataFrame({'key': ['foo', 'bar'], 'lval': [1, 2]})
right = pd.DataFrame({'key': ['foo', 'bar'], 'rval': [4, 5]})
# 按 key 列合并
pd.merge(left, right, on='key')
9. 分组 (GroupBy) 与 透视表
这是数据分析中“灵魂”般的操作。
9.1 GroupBy
“拆分(Split) - 应用(Apply) - 合并(Combine)”
df_group = pd.DataFrame({
'A': ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'bar'],
'B': ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'],
'C': np.random.randn(8),
'D': np.random.randn(8)
})
# 按 A 列分组,并求和
print(df_group.groupby('A').sum())
# 按 A, B 两列分组求和
print(df_group.groupby(['A', 'B']).sum())
9.2 透视表 (Pivot Table)
类似于 Excel 的透视表。
# 以前面的 df_group 为例
# values: 要统计的数据, index: 行, columns: 列
pd.pivot_table(df_group, values='D', index=['A', 'B'], columns=['C']) # C 列因为是 float 不适合做 column,这里仅作语法演示
10. 时间序列
Pandas 在处理时间序列方面非常强大。
# 生成时间序列 (按秒)
rng = pd.date_range('1/1/2022', periods=100, freq='S')
# 重采样 (Resample): 将高频数据变为低频 (如 秒 -> 5分钟)
ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng)
# 求每分钟的总和
ts.resample('1Min').sum()
K 线周期转换示例:
# 模拟日线数据
dates_k = pd.date_range('2022-01-01', periods=20, freq='D')
df_k = pd.DataFrame(np.random.randn(20, 4), index=dates_k, columns=['open', 'high', 'low', 'close'])
# 将日线转换为周线 (W), 并指定每列的处理方式
weekly_df = df_k.resample('W').agg({
'open': 'first', # 周开盘 = 第一天开盘
'high': 'max', # 周最高 = 最大的最高
'low': 'min', # 周最低 = 最小的最低
'close': 'last' # 周收盘 = 最后一天收盘
})
print(weekly_df)
11. 绘图
Pandas 集成了 Matplotlib,可以直接画图。
import matplotlib.pyplot as plt
# 简单的折线图
ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2020', periods=1000))
ts = ts.cumsum() # 累加,模拟走势
ts.plot()
plt.show()
# DataFrame 绘图 (绘制所有列)
df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list('ABCD'))
df = df.cumsum()
df.plot()
plt.show()