pandas
环境配置与导入
在开始之前,需要导入核心库。通常约定俗成的别名如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置显示选项(可选,用于美观)
pd.options.display.max_rows = 10 # 默认显示10行,超过会折叠
核心数据结构:Series (一维)
Series 就像一个加强版的 Python 列表,或者 Excel 中的一列数据。它由数据和索引组成。
2.1 Series 的创建
- 从列表创建:默认生成整数索引
0, 1, 2...
obj = pd.Series([4, 7, -5, 3])
# 输出:
# 0 4
# 1 7
# 2 -5
# 3 3
# dtype: int64
- 带标签的索引:指定
index参数,索引可以是字符串。
obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
- 从字典创建:字典的键会自动作为索引。
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000}
obj3 = pd.Series(sdata)
# 输出:
# Ohio 35000
# Texas 71000
# Oregon 16000
# dtype: int64
2.2 Series 的属性与操作
-
查看数据和索引:
-
obj.values:返回底层的 NumPy 数组。 -
obj.index:返回索引对象。
-
-
索引与切片:
-
标签索引:
obj2['a'](返回 -5)。 -
位置索引:
obj2[2](返回 -5)。 -
切片:
obj2['b':'c'](包含末端 ‘c’)。
-
-
向量化运算:
- 支持 NumPy 的数组运算,如
obj * 2,np.exp(obj)。
- 支持 NumPy 的数组运算,如
-
处理缺失值:
-
pd.isnull(obj)/obj.isnull():检查是否为 NaN。 -
pd.notnull(obj)/obj.notnull():检查是否非空。
-
核心数据结构:DataFrame (二维)
DataFrame 就像 Excel 表格或 SQL 表,是 Pandas 中最常用的数据结构。
3.1 DataFrame 的创建
- 从字典创建:字典的键是列名,值是列数据。
data = {
'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9]
}
frame = pd.DataFrame(data)
- 自定义列顺序:传入
columns参数。
pd.DataFrame(data, columns=['year', 'state', 'pop'])
- 带索引:传入
index参数。
frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five'])
# 注意:如果列名在字典中不存在(如 'debt'),该列会初始化为 NaN。
3.2 DataFrame 的属性
-
frame.columns:获取列名索引。 -
frame.index:获取行索引。 -
frame.values:获取底层的二维 NumPy 数组。
3.3 列的操作
-
获取列:
-
frame['state'](返回一个 Series)。 -
frame.state(属性访问法,仅限简单列名)。
-
-
修改列:
-
frame['debt'] = 16.5(赋值给整列)。 -
frame['debt'] = np.arange(5.)(赋值给数组)。
-
-
添加新列:如果列不存在,直接赋值即可创建新列。
-
删除列:
del frame['debt']。
3.4 行的操作 (索引)
-
获取行:
-
位置索引:
frame.iloc[1](获取第 2 行)。 -
标签索引:
frame.loc['two'](获取标签为 ‘two’ 的行)。
-
-
切片行:
frame[:2](获取前两行)。
基本功能与运算
认识了 Series 和 DataFrame 两种结构后,接下来是它们通用的基本操作。
4.1 重新索引
reindex() 方法用于创建一个新对象,其数据符合新索引。
obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
# 输出:e 对应的值为 NaN (缺失值)
- 填充缺失值:使用
method='ffill'(前向填充) 或method='bfill'(后向填充)。
4.2 丢弃条目
drop() 方法用于删除行或列。
# 删除行
obj.drop('a')
# 删除列 (axis=1)
frame.drop(['year', 'state'], axis=1)
4.3 算术运算与对齐
Pandas 在进行算术运算时会自动对齐索引。
-
Series 间运算:索引对齐,缺失值产生 NaN。
-
DataFrame 间运算:列和行索引都会对齐。
-
广播机制:类似 NumPy,可以沿着行或列进行广播。
数据清洗与处理
真实数据很少是干净的,这一节整理缺失值处理和层次化索引这两个常见问题。
5.1 处理缺失值
-
检测:
isnull()/notnull()。 -
删除:
dropna()。-
how='all':只删除全为 NaN 的行/列。 -
thresh=2:保留至少有 2 个非 NaN 值的行。
-
-
填充:
fillna()。-
fillna(0):填充 0。 -
fillna(method='ffill'):前向填充。 -
fillna({'A': 0, 'B': 1}):按列填充不同值。
-
5.2 层次化索引
Pandas 允许拥有多个(层级)索引。
# 创建 MultiIndex
arrays = [['bar', 'bar', 'baz', 'baz'], ['one', 'two', 'one', 'two']]
index = pd.MultiIndex.from_arrays(arrays, names=['first', 'second'])
s = pd.Series(np.random.randn(4), index=index)
# 选择数据
s['bar'] # 选择第一层索引
s.loc # 选择多层索引
总结
这份笔记涵盖了文档中的所有核心概念,建议你结合 Jupyter Notebook 实际运行代码加深理解。
Pandas 高效数据处理实战指南
前一部分梳理了概念,这一部分换成场景导向:每个技巧按「应用场景 — 核心语法 — 原理解析」组织,先从最基础的准备工作开始。
1.1 版本检查 (Version Check)
-
应用场景:在复现他人代码或排查兼容性问题时,首先确认 Pandas 版本。
-
核心语法:
import pandas as pd
pd.__version__
- 原理解析:直接访问模块的
version属性,返回当前安装的版本号字符串。
1.2 快速构建 DataFrame
-
应用场景:编写教程、测试函数逻辑或创建小型示例数据时,避免读取外部文件。
-
核心语法:
- 字典法(适合少量结构化数据):
df = pd.DataFrame({'col_one': [1, 2], 'col_two': [3, 4]})- 随机数法(适合大规模性能测试):
import numpy as np df = pd.DataFrame(np.random.rand(4, 8), columns=list('abcdefgh')) -
原理解析:利用 Python 字典键值对映射列名与数据,或利用 NumPy 生成随机矩阵快速填充。
1.3 列名标准化 (Renaming Columns)
-
应用场景:原始数据列名包含空格、特殊字符或大小写不统一,导致代码调用困难。
-
核心语法:
- 指定重命名:
df.rename({'old name': 'new_name'}, axis='columns', inplace=True) # 或简写 df.rename(columns={'old name': 'new_name'}, inplace=True)- 批量格式化(去除空格并转下划线):
df.columns = df.columns.str.replace(' ', '_').str.lower() -
原理解析:
rename方法通过字典映射修改标签;.str访问器允许对 Index 对象进行向量化字符串操作。
1.4 序列反转 (Reversing Order)
-
应用场景:时间序列数据需要倒序查看,或需要反转行顺序以匹配其他数据源。
-
核心语法:
df_reversed = df.iloc[::-1].reset_index(drop=True)
-
原理解析:
-
iloc[::-1]:利用 Python 切片步长为 -1 的特性,实现行索引的完全反转。 -
reset_index(drop=True):反转后原索引顺序错乱,此步骤丢弃旧索引并生成新的连续整数索引。
-
第二章:数据清洗与类型转换
处理“脏数据”是数据分析中最耗时的环节,本章重点解决类型不一致和格式不规范问题。
2.1 按数据类型筛选列
-
应用场景:只想对数值列进行统计,或只想对文本列进行清洗,无需手动列出列名。
-
核心语法:
# 仅选择数值型列
df_num = df.select_dtypes(include='number')
# 仅选择对象型(字符串)列
df_obj = df.select_dtypes(include='object')
# 排除特定类型
df_no_float = df.select_dtypes(exclude='float')
- 原理解析:
select_dtypes根据 NumPy 的 dtype 系统自动过滤列,支持include(包含)和exclude(排除)逻辑。
2.2 鲁棒的数值转换 (Robust Numeric Conversion)
-
应用场景:列中混入了非数值字符(如
'-','N/A','unknown'),直接使用astype(int)会报错。 -
核心语法:
# 强制转换,无法转换的变为 NaN,然后填充为 0
df['col'] = pd.to_numeric(df['col'], errors='coerce').fillna(0)
-
原理解析:
-
errors='coerce':遇到解析错误时不抛出异常,而是将其转换为NaN(Not a Number)。 -
.fillna(0):随后将产生的缺失值填充为默认值(如 0),保证数据完整性。
-
2.3 缺失值的高级处理
-
应用场景:数据集中存在大量缺失值,需要根据缺失比例决定是删除列还是保留。
-
核心语法:
- 统计缺失:
df.isna().sum() # 每列缺失数量- 按阈值删除列(删除缺失率超过 10% 的列):
threshold = len(df) * 0.9 # 至少保留 90% 的非空值 df_clean = df.dropna(thresh=threshold, axis='columns')
2.4 字符串拆分扩列
-
应用场景:单列中包含复合信息(如 “FirstName LastName” 或 “City, State”),需拆分为多列。
-
核心语法:
# 将 'name' 列按空格拆分,expand=True 表示展开为 DataFrame
df[['first', 'last']] = df['name'].str.split(' ', n=1, expand=True)
- 原理解析:
.str.split()默认返回列表,设置expand=True后,Pandas 会自动将列表元素展开为独立的列。n=1限制只分割一次,防止名字中间有空格导致列数过多。
第三章:多源数据整合
当数据分散在多个文件或不同维度时,如何高效合并。
3.1 批量合并多个文件 (行堆叠)
-
应用场景:日志文件、分月的销售报表等格式相同但存储在不同 CSV 文件中,需合并为一张大表。
-
核心语法:
from glob import glob
# 1. 获取文件列表
files = sorted(glob('data/stocks*.csv'))
# 2. 使用生成器表达式读取并合并
df_all = pd.concat((pd.read_csv(f) for f in files), ignore_index=True)
-
原理解析:
-
glob:利用通配符匹配文件系统路径。 -
ignore_index=True:合并后重新生成连续索引,避免索引重复。
-
3.2 横向拼接数据 (列合并)
-
应用场景:同一组样本的不同特征存储在不同的 DataFrame 中,需按行索引对齐合并。
-
核心语法:
df_combined = pd.concat([df_left, df_right], axis='columns')
- 原理解析:
axis='columns'(或axis=1) 指示 Pandas 沿水平方向拼接。Pandas 会自动基于索引(Index)进行对齐,索引不匹配的位置会自动填充 NaN。
第四章:高级筛选与过滤
从海量数据中精准提取子集,超越基础的布尔索引。
4.1 多条件成员资格筛选
-
应用场景:筛选出属于多个特定类别的行(例如:只看 “Action” 和 “Drama” 类型的电影)。
-
核心语法:
# 推荐写法
mask = df['genre'].isin(['Action', 'Drama', 'Sci-Fi'])
df_filtered = df[mask]
# 不推荐写法 (冗长且易错)
# df[(df.genre == 'Action') | (df.genre == 'Drama') | ...]
- 原理解析:
isin()方法接受一个列表,返回一个布尔 Series,效率远高于链式的|(OR) 操作,且代码可读性更强。
4.2 基于频率的动态筛选
-
应用场景:只关注出现频率最高的前 N 个类别,忽略长尾数据。
-
核心语法:
# 1. 计算频次
counts = df['genre'].value_counts()
# 2. 获取前 3 名的索引(即类别名称)
top_3_genres = counts.nlargest(3).index
# 3. 筛选
df_top = df[df['genre'].isin(top_3_genres)]
- 原理解析:结合
value_counts()统计频次,nlargest()快速提取 Top N,最后再次利用isin()完成过滤。这是一套标准的“统计 - 提取 - 过滤”组合拳。
第五章:聚合分析与数据重塑
数据的终极价值在于汇总与形态转换,以支持决策和可视化。
5.1 多函数同时聚合
-
应用场景:分组后需要同时查看总和、平均值、计数等多个统计量。
-
核心语法:
# 对 'item_price' 列同时计算 sum 和 count
result = df.groupby('order_id')['item_price'].agg(['sum', 'count', 'mean'])
- 原理解析:
agg()(aggregate) 方法接受函数名列表或字典,允许在一次groupby操作中执行多种计算,避免了多次分组带来的性能损耗。
5.2 统计结果的切片查看
-
应用场景:
describe()生成的统计表信息量过大,只需关注其中几行(如 min, max)和几列。 -
核心语法:
# 先描述,再行切片 ['min':'max'],再列切片 ['Pclass':'Parch']
summary = df.describe().loc['min':'max', 'Pclass':'Parch']
- 原理解析:
describe()返回的 DataFrame 其索引是统计量名称(count, mean, std…)。利用.loc可以像操作普通数据一样对这些统计结果进行二次筛选。
5.3 透视表化:unstack 操作
-
应用场景:将多级索引(MultiIndex)的 Series 转换为更易读的宽表(DataFrame),常用于热力图绘制。
-
核心语法:
# 分组计算均值,得到 MultiIndex Series
s = df.groupby(['Sex', 'Pclass'])['Survived'].mean()
# 将最内层索引 ('Pclass') 转为列
df_wide = s.unstack()
- 原理解析:
unstack()是stack()的逆运算,它将指定的行索引层级“旋转”为列索引,从而改变数据的维度结构(从长表变宽表)。
5.4 连续变量离散化 (Binning)
-
应用场景:将连续的数值(如年龄、收入)划分为离散的区间(如“青年”、“中年”、“老年”),以便进行分组分析。
-
核心语法:
# 定义 bins 边界和对应的标签
bins = [0, 18, 35, 60, 100]
labels = ['Child', 'Young Adult', 'Adult', 'Senior']
df['Age_Group'] = pd.cut(df['Age'], bins=bins, labels=labels, right=False)
- 原理解析:
pd.cut()根据给定的边界将数值映射到对应的区间标签中。生成的新列是Categorical类型,非常适合用于groupby操作。参数right=False表示区间为左闭右开[ ),可根据需求调整。