简介:这份 Numpy and Pandas Cheat Sheet 面向刚接触 Python 数据分析的初学者与需要快速查阅常用 API 的开发者,用一页速查表的形式梳理两大核心库的高频操作,帮助解决语法记不牢、函数调用易混淆的问题。资源为单个 PDF 文件,压缩包约 67KB,内容涵盖导入约定、Numpy 向量化运算与 Matplotlib 绘图、Pandas 的 Series 与 DataFrame 索引访问、统计汇总、apply 函数应用、条件过滤、分组排序、合并连接、缺失值处理及字符串与日期清洗等模块,并附有常见函数速查条目。目前已有 193 人学习下载,适合作为日常编码时的案头参考,也可用于系统复习数据分析基础操作,配合 Seaborn 可视化快速上手真实项目。
1. 从一份速查表说起:为什么 NumPy 和 Pandas 总是被放在一起学
很多人第一次打开数据分析的入门材料,看到的就是一份把 NumPy 和 Pandas 常用操作并排罗列的速查表。它看起来像两张互不相干的清单:一边是数组的创建、切片、广播,另一边是表格的筛选、分组、连接。真正上手做项目才会发现,这两者从来不是并列关系,而是上下游关系——NumPy 负责数值计算的底层内存与向量化,Pandas 负责带标签的表格组织与业务语义。一份好的速查表,价值不在于让你背下所有函数名,而在于让你在遇到「这列数据怎么按条件替换」「这个矩阵怎么按行归一化」时,能立刻判断该翻到哪一页。
这份速查表适合三类人:刚转行做数据分析、还在被axis参数绕晕的新手;写惯了循环、想把手写for换成向量化的熟手;以及需要把零散操作固化成可复用片段的一线工程师。下面我不逐条翻译速查表,而是把它拆成能直接抄进项目的操作路径,顺带把那些速查表不会写的参数边界和翻车点讲清楚。
2. 先把 NumPy 的数组操作跑通:从创建到广播的四个关键动作
2.1 创建与形状:别让一维数组悄悄变成二维
速查表里np.array、np.zeros、np.arange通常只占一行,但形状问题往往在后续运算才爆发。我一般会在创建后立刻打印.shape和.ndim,尤其是从列表嵌套结构转换时。
import numpy as np # 从嵌套列表创建,注意中括号层数决定维度 a = np.array([[1, 2, 3], [4, 5, 6]]) # shape (2, 3) b = np.array([1, 2, 3]) # shape (3,) 一维 c = np.zeros((2, 3), dtype=np.float32) # 指定 dtype 避免后续隐式转换 d = np.arange(0, 10, 2) # [0 2 4 6 8] print(a.shape, a.ndim) # (2, 3) 2 print(b.shape, b.ndim) # (3,) 1 print(c.dtype) # float32逻辑说明:np.array的维度由嵌套层数决定,[[...]]是二维,[...]是一维。参数上,dtype建议显式指定,默认float64在内存敏感场景会翻倍。np.arange的第三个参数是步长,不包含终点值,这点和 Python 内置range一致,但和np.linspace不同——后者包含终点,且第三个参数是点数而非步长。
2.2 索引与切片:视图和副本的区别决定你会不会改坏原数据
速查表通常只写a[1:3],但不会强调切片返回的是视图。对视图赋值会改到原数组,这是血泪经验里最常见的一类 bug。
a = np.arange(10) view = a[2:5] # 视图,共享内存 view[0] = 999 print(a) # [0 1 999 3 4 5 6 7 8 9] 原数组被改 copy = a[2:5].copy() # 显式副本 copy[0] = -1 print(a) # 原数组不受影响逻辑说明:基础切片(冒号)返回视图,花式索引(整数数组)返回副本。参数上,.copy()是后悔药,不确定时加上它,代价是一次内存拷贝。布尔索引也返回副本,所以a[a > 5] = 0这种写法是安全的,它直接在原数组上按掩码赋值。
2.3 广播:形状对齐规则和三个必调参数
广播是 NumPy 最容易被玄学化的部分。规则其实只有一条:从右往左逐维比较,维度相等或其中一个为 1 即可广播,否则报错。
x = np.ones((3, 4)) y = np.arange(4) # shape (4,) z = x + y # y 广播成 (3, 4) col = np.arange(3).reshape(3, 1) # shape (3, 1) w = x + col # col 广播成 (3, 4) # 下面这行会报错,因为 3 和 4 不相等且都不为 1 # bad = np.ones((3, 4)) + np.arange(3)逻辑说明:reshape(3, 1)把一维变成列向量,这是做按行归一化、减均值等操作的常用手法。参数上,reshape可以用-1让 NumPy 自动推断某一维,例如reshape(3, -1)。如果广播报错,先打印两个数组的.shape,从右往左对齐看,基本能定位问题。
2.4 向量化替代循环:一个归一化的完整例子
速查表会列np.mean、np.std,但不会告诉你如何组合成按列标准化。下面这个片段可以直接抄。
data = np.random.randn(100, 5) # 100 行 5 列 mean = data.mean(axis=0) # 每列均值,shape (5,) std = data.std(axis=0) # 每列标准差 normalized = (data - mean) / std # 防止除零,加一个极小值 normalized_safe = (data - mean) / (std + 1e-8)逻辑说明:axis=0表示沿行方向压缩,得到每列统计量;axis=1则是每行。参数上,std默认除以 N,若需要样本标准差要传ddof=1。1e-8是工程习惯,避免某列方差为零时出现 inf。这套写法比双重循环快一到两个数量级,且没有中间列表开销。
3. Pandas 的表格操作:筛选、分组、连接怎么写得又快又稳
3.1 筛选与赋值:loc 和 iloc 的边界,以及链式赋值的坑
速查表会写df[df['a'] > 0],但涉及赋值时,必须用.loc明确行列,否则触发SettingWithCopyWarning。
import pandas as pd df = pd.DataFrame({ 'name': ['A', 'B', 'C', 'D'], 'score': [85, 92, 78, 95], 'group': ['x', 'y', 'x', 'y'] }) # 条件筛选 high = df[df['score'] >= 90] # 安全赋值:loc[行条件, 列名] df.loc[df['score'] < 80, 'level'] = 'low' df.loc[df['score'] >= 80, 'level'] = 'high' # iloc 按位置,左闭右开 first_two_rows = df.iloc[0:2, 0:2]逻辑说明:.loc按标签,.iloc按整数位置。链式写法df[df['a'] > 0]['b'] = 1在 Pandas 中可能只改到临时副本,这是最常见的翻车点。参数上,.loc的行条件可以是布尔 Series,列名可以是单个字符串或列表。如果列不存在,.loc赋值会新建列,这点和直接df['new'] = ...效果一致,但前者更可控。
3.2 分组聚合:groupby 的三种输出形态和 agg 的用法
速查表通常只给df.groupby('key').mean(),但实际业务需要多列不同聚合、自定义函数、以及重置索引。
# 单列聚合 mean_score = df.groupby('group')['score'].mean() # 多列多函数 agg_result = df.groupby('group').agg( avg_score=('score', 'mean'), max_score=('score', 'max'), count=('name', 'count') ).reset_index() # 自定义聚合 def score_range(s): return s.max() - s.min() custom = df.groupby('group')['score'].agg(score_range)逻辑说明:agg的命名聚合写法(新列名=('原列', '函数'))是 Pandas 较新版本推荐的,输出列名清晰。参数上,reset_index()把分组键从索引变回普通列,方便后续合并。自定义函数接收的是 Series,返回标量。如果分组后想保留原表行数,用transform而不是agg。
3.3 连接与合并:merge 的四种连接方式和索引对齐
速查表会列merge、join、concat,但容易混淆。我一般统一用merge,因为连接键和方式最明确。
left = pd.DataFrame({'id': [1, 2, 3], 'a': ['x', 'y', 'z']}) right = pd.DataFrame({'id': [2, 3, 4], 'b': ['p', 'q', 'r']}) inner = pd.merge(left, right, on='id', how='inner') # 交集 outer = pd.merge(left, right, on='id', how='outer') # 并集 left_j = pd.merge(left, right, on='id', how='left') # 保留左表 right_j = pd.merge(left, right, on='id', how='right')# 保留右表逻辑说明:how参数控制连接方式,默认inner。参数上,如果两表连接键名不同,用left_on和right_on。连接后会出现_x、_y后缀,用suffixes自定义。concat适合纵向堆叠,axis=0按行,axis=1按列,但按列时是按索引对齐,容易产生大量 NaN,不如merge直观。
3.4 缺失值与类型转换:fillna、astype 和 category 的取舍
速查表会列isnull、fillna、dropna,但类型转换的坑往往在内存和后续运算上。
df2 = pd.DataFrame({ 'v': [1.0, np.nan, 3.0], 'g': ['a', 'b', 'a'] }) # 填充缺失 df2['v_filled'] = df2['v'].fillna(df2['v'].mean()) # 类型转换 df2['v_int'] = df2['v_filled'].astype(int) # 类别类型,适合低基数列 df2['g_cat'] = df2['g'].astype('category') print(df2['g_cat'].cat.categories)逻辑说明:fillna可以传标量、字典或 Series。astype(int)要求没有 NaN,否则报错,所以先填充。category类型在低基数列上能显著省内存,且分组聚合更快,但插入新类别时需要先更新 categories。参数上,astype转换失败会抛异常,可以用pd.to_numeric(..., errors='coerce')把无法转换的变成 NaN。
4. 避坑与排查:速查表不会写的五条实战教训
4.1 现象:修改切片后原数组变了;原因:视图共享内存;解决:不确定就.copy()
NumPy 的基础切片返回视图,这是设计如此,不是 bug。排查方法:打印view.base,如果不是 None,说明它是某个数组的视图。解决方式是在切片后加.copy(),或者在创建时就明确是否需要独立内存。Pandas 的切片行为又不同,df[0:2]返回副本,但.loc切片在某些版本返回视图,所以赋值一律用.loc明确行列。
4.2 现象:SettingWithCopyWarning反复出现;原因:链式索引;解决:用.loc一步到位
这个警告不是报错,但意味着你的赋值可能没生效。典型触发是df[df['a'] > 0]['b'] = 1。原因是第一步筛选返回副本,第二步赋值改的是副本。解决方式是合并成df.loc[df['a'] > 0, 'b'] = 1。如果确实需要先筛选再操作,用.copy()显式创建新 DataFrame,后续操作都在新表上。
4.3 现象:groupby后列不见了;原因:分组键变成索引;解决:reset_index()或as_index=False
df.groupby('g')['v'].mean()返回的 Series 索引是分组键,不是列。如果后续要merge,索引对不上。两种解决:一是.reset_index()把索引变列;二是groupby('g', as_index=False)直接保留列结构。参数上,as_index=False在多列聚合时更直观,但命名聚合写法下reset_index()更通用。
4.4 现象:merge后行数变多;原因:连接键有重复值;解决:先检查唯一性
merge默认是内连接,如果右表连接键有重复,结果会笛卡尔积式膨胀。排查方法:right['id'].duplicated().sum()看重复数量。解决方式:先去重right.drop_duplicates(subset='id'),或者明确用validate='one_to_one'让 Pandas 在键不唯一时报错。参数上,validate可选one_to_one、one_to_many、many_to_one、many_to_many,是防止意外膨胀的好工具。
4.5 现象:内存爆掉;原因:默认float64和object类型;解决:降位宽和转category
NumPy 默认float64,Pandas 读 CSV 时数值列也是float64,字符串列是object。对于百万行数据,把float64降到float32能省一半内存,把低基数字符串转category能省更多。排查方法:df.memory_usage(deep=True)看每列占用。解决方式:读入时指定dtype,或读入后批量astype。注意float32精度约 7 位有效数字,金融计算慎用。
5. 把速查表变成自己的工具箱:三个进阶习惯
5.1 用pipe把多步操作串成可读流水线
当清洗步骤超过五步,嵌套写法会变成黑匣子。pipe让每一步都是一个函数,顺序清晰,中间结果可打印。
def drop_na_rows(df, cols): return df.dropna(subset=cols) def add_ratio(df, num, den): df = df.copy() df['ratio'] = df[num] / df[den] return df result = ( df.pipe(drop_na_rows, cols=['score']) .pipe(add_ratio, num='score', den='score') )逻辑说明:pipe把 DataFrame 作为第一个参数传给函数,函数返回 DataFrame。参数上,额外参数通过pipe的关键字传入。这种写法在调试时可以在任意一步插入print或断点,比一长串链式调用更容易定位问题。
5.2 用query和eval写复杂条件,但注意作用域
query让筛选条件接近自然语言,列名含空格时用反引号。
df3 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}) filtered = df3.query('a > 1 and b < 6') # 引用外部变量用 @ threshold = 2 filtered2 = df3.query('a > @threshold')逻辑说明:query底层用numexpr加速,大数据量下比布尔索引快。参数上,外部变量必须加@前缀,否则会被当成列名。eval类似,用于计算新列,例如df3.eval('c = a + b', inplace=True)。注意inplace在 Pandas 新版本中逐渐被弃用,建议用赋值写法。
5.3 验证习惯:每一步都检查形状和缺失值
我自己的习惯是每做完一步转换,就打印shape和isnull().sum()。这不是强迫症,而是因为数据分析的 bug 往往不报错,只是结果悄悄偏了。比如merge后行数变了、groupby后某些组消失了、astype把异常值变成了 NaN。一个简单的检查函数就能省下大量回头排查的时间。
def check(df, step_name): print(f"[{step_name}] shape={df.shape}, nulls={df.isnull().sum().sum()}") return df result = ( df.pipe(check, 'raw') .pipe(drop_na_rows, cols=['score']) .pipe(check, 'after_dropna') )逻辑说明:check返回原 DataFrame,所以可以无缝插入pipe链。参数上,isnull().sum().sum()统计全表缺失总数,若要看每列,去掉最后一个.sum()。这个习惯在多人协作时尤其有用,别人看你的 notebook 能清楚知道每一步的数据形态。
最后说一句我自己的教训:早年我总想背下速查表里所有函数,后来发现真正有用的是记住「什么场景该翻哪一页」,以及每个操作背后的形状、类型、内存代价。速查表是地图,不是终点。希望帮到你。
本文还有配套的精品资源,点击获取