简介这份 Numpy and Pandas Cheat Sheet 面向刚接触 Python 数据分析的初学者与需要快速查阅常用 API 的开发者用一页速查表的形式梳理两大核心库的高频操作帮助解决语法记不牢、函数调用易混淆的问题。资源包共 1 个文件为 67KB 的 PDF 文档便于打印或随查随用。内容覆盖导入 numpy、pandas、matplotlib、seaborn 的常用写法Numpy 的向量化运算元素级加减、按位与或非、比较运算与直方图、散点图、线图绘制以及 Pandas 中 Series 的 iloc/loc 索引、values 取值、max/min/mean/median/sum 统计、apply 函数应用、条件筛选、groupby 分组、sort_values 排序、concat 与 merge 合并、dropna 与 fillna 缺失值处理、字符串清洗和 to_datetime 日期转换等。目前已有 193 人学习适合作为日常数据分析的案头速查工具也可配合 Seaborn 可视化快速上手实战。1. 一份被低估的速查表为什么老手也把它压在键盘底下刚入行那会儿我总觉得“速查表”是给记不住 API 的新手用的。直到有次赶一个数据清洗的活凌晨两点对着一个axis参数反复试错才意识到问题不在记性而在上下文切换的成本。你正沉浸在业务逻辑里突然要确认df.apply和df.applymap的返回类型差异切浏览器、搜关键词、翻三页才找到答案——这种打断一次两次无所谓一天来二十次思路就碎成渣了。这份《Numpy and Pandas Cheat Sheet.pdf》解决的正是这个场景。它把 Numpy 的向量化运算、Pandas 的 Series/DataFrame 访问、函数应用、汇总统计、绘图接口压缩在几页里按“操作意图”而不是“API 字母序”组织。适合两类人一是刚学完基础语法、写代码时频繁卡在“这个功能该用哪个方法”的转行者二是天天和表格打交道、但懒得记axis0和axis1到底谁是谁的从业者。它不教你数据分析思维但能让你在实现思路清晰时少花一半时间在查语法上。我后来把它打印出来贴在显示器边框上翻得最多的是apply家族和axis参数那两页。下面按我实际使用的顺序拆解这份速查表里真正高频、且容易踩坑的部分。2. 向量化运算与 axis 参数速查表里最容易看走眼的两块2.1 向量化运算不只是“不用写循环”速查表开篇列了xs ys、xs z、xs ys、xs | ys、~xs、xs ys这些操作。表面看是语法糖实际是 Numpy 的核心执行模型对整块内存做批量操作而不是逐个元素走 Python 解释器。这意味着两件事——第一代码短第二如果形状不匹配报错也来得更直接。我见过不少人把xs ys当成“两个列表相加”来理解结果遇到xs是(3,)、ys是(3,1)时得到一个(3,3)的矩阵还以为是 bug。这其实是广播机制在起作用。速查表没展开讲广播规则但你在实际用的时候必须心里有数从右往左对齐维度要么相等要么其中一个是 1。import numpy as np xs np.array([1, 2, 3]) ys np.array([10, 20, 30]) z 5 # 元素级加法形状相同逐位相加 print(xs ys) # [11 22 33] # 向量加标量标量广播到每个元素 print(xs z) # [6 7 8] # 布尔运算返回布尔数组常用于条件筛选 mask (xs 1) (ys 30) print(mask) # [False True False] # 广播陷阱列向量 行向量 col np.array([[1], [2], [3]]) # 形状 (3,1) row np.array([10, 20, 30]) # 形状 (3,) print(col row) # 形状 (3,3)不是 (3,)上面这段代码里col row的结果是 3×3 矩阵因为(3,1)和(3,)广播后变成(3,3)。如果你本意是逐行相加应该先把row转成(3,1)或者用col row.reshape(-1,1)。这个坑我在处理传感器多通道数据时踩过——以为在算差值实际在算外积后面统计全错。提示速查表里xs ys和xs | ys只对布尔数组或整数按位运算有意义。如果你拿两个浮点数组做Numpy 会直接报类型错误不会自动转成逻辑与。逻辑与要用np.logical_and(xs, ys)。2.2 axis0 和 axis1速查表写了但没告诉你记忆方法速查表里df.mean(axis0)标注“mean of each column”df.mean(axis1)标注“mean of each row”。文字是对的但很多人看完还是记不住。我自己的记忆方法是axis 是你想要“压扁”的那个维度。axis0压扁行方向剩下列所以是对每一列求统计axis1压扁列方向剩下行所以是对每一行求统计。import pandas as pd df pd.DataFrame({ A: [1, 2, 3], B: [4, 5, 6], C: [7, 8, 9] }) # axis0沿着行方向压扁对每一列求均值 print(df.mean(axis0)) # A 2.0 # B 5.0 # C 8.0 # axis1沿着列方向压扁对每一行求均值 print(df.mean(axis1)) # 0 4.0 # 1 5.0 # 2 6.0 # 字符串别名等价写法速查表里也列了 print(df.mean(axisindex)) # 同 axis0 print(df.mean(axiscolumns)) # 同 axis1参数说明axis接受0/1或index/columns。我一般用数字因为少打几个字符但在写给别人看的 notebook 里会用字符串别名可读性更好。注意df.mean(axis0)返回的是 Series索引是列名df.mean(axis1)返回的 Series 索引是行索引。如果你后续要把结果合并回原 DataFrame索引对齐这一步不能想当然。还有一个容易翻车的地方df.dropna(axis0)和df.dropna(axis1)的含义跟mean一致但作用对象是缺失值。axis0是“只要这一行有 NaN 就删行”axis1是“只要这一列有 NaN 就删列”。我见过有人想删列结果写了axis0数据少了一半还找不到原因。3. 数据访问三件套iloc、loc、values 的边界与转换成本3.1 iloc 和 loc 不是“随便选一个就行”速查表把s.iloc[i]、s.loc[x]、df.iloc[i, j]、df.loc[x, y]并列列出但没强调两者的本质区别iloc 按位置loc 按标签。位置是整数从 0 开始标签是索引里实际存的值可能是字符串、日期、甚至浮点数。import pandas as pd s pd.Series([10, 20, 30], index[a, b, c]) # iloc按位置永远从 0 开始 print(s.iloc[0]) # 10 print(s.iloc[-1]) # 30 # loc按标签索引里是什么就用什么 print(s.loc[a]) # 10 print(s.loc[c]) # 30 # 切片行为不同iloc 左闭右开loc 左闭右闭 print(s.iloc[0:2]) # a10, b20不含位置 2 print(s.loc[a:b]) # a10, b20含标签 b这个切片差异是血泪经验用iloc切片时结束位置不包含用loc切片时结束标签包含。如果你从iloc切到loc没注意边界数据就会多一条或少一条。我处理按日期索引的销售数据时用loc[2024-01-01:2024-01-31]能拿到整月但换成iloc就得自己算位置很容易差一天。注意如果 DataFrame 的索引是默认的RangeIndex0,1,2...iloc和loc在数值上看起来一样但语义不同。一旦你做了set_index或筛选两者就分道扬镳了。速查表里没写这个前提但实际用的时候必须清楚。3.2 values 和 apply转换与逐行操作的性能分界线s.values和df.values返回的是 Numpy 数组。速查表标注“Get NumPy array”但没提什么时候该转、什么时候不该转。我的经验是如果你接下来要做纯数值计算矩阵乘法、广播、FFT转成 Numpy 数组更快如果你还要保留列名、索引、混合类型就别转转了反而丢信息。import pandas as pd import numpy as np df pd.DataFrame({ name: [A, B, C], score: [85, 92, 78] }) # 转成 Numpy 数组混合类型会变成 object 数组 arr df.values print(arr.dtype) # object print(arr.shape) # (3, 2) # 只取数值列转数组保持 float 类型 scores df[score].values print(scores.dtype) # int64 # apply对 Series 逐元素或对 DataFrame 逐列/逐行操作 df[score_plus] df[score].apply(lambda x: x 5) print(df) # name score score_plus # 0 A 85 90 # 1 B 92 97 # 2 C 78 83 # applymap对 DataFrame 每个元素操作Pandas 2.1 建议用 map df_num df[[score, score_plus]] df_doubled df_num.applymap(lambda x: x * 2) print(df_doubled)参数说明apply在 Series 上是逐元素在 DataFrame 上是逐列默认axis0或逐行axis1。applymap是逐元素但只对 DataFrame 有效。速查表里写了df.apply(series - value)返回 Seriesdf.apply(series - series)返回 DataFrame——这个区别决定了你后面能不能直接赋值回去。如果函数返回标量得到 Series如果返回 Series得到 DataFrame。性能上apply本质是 Python 循环比向量化慢一到两个数量级。我一般只在逻辑复杂、无法向量化时才用。比如根据多列条件打标签用np.select或np.where比apply快得多。速查表没写性能对比但你在处理超过十万行的数据时这个选择会直接决定脚本是跑三秒还是跑三分钟。4. 汇总、绘图与函数应用速查表里那些“看起来简单但容易翻车”的接口4.1 describe 和 head/tail快速体检的正确打开方式df.describe()输出每列的计数、均值、标准差、四分位数。速查表标注“Stats about each column”但实际用的时候要注意它默认只统计数值列。如果你的 DataFrame 有字符串列describe 会直接跳过不会报错也不会提示。我见过有人拿 describe 的结果当“数据全貌”结果漏掉了类别列的分布问题。import pandas as pd df pd.DataFrame({ age: [23, 45, 31, 52, 38], city: [A, B, A, C, B], salary: [5000, 8000, 6000, 12000, 9000] }) # 默认只统计数值列 print(df.describe()) # age salary # count 5.000000 5.000000 # mean 37.800000 7400.000000 # std 11.432407 2645.751310 # min 23.000000 5000.000000 # 25% 31.000000 6000.000000 # 50% 38.000000 8000.000000 # 75% 45.000000 9000.000000 # max 52.000000 12000.000000 # 包含类别列需要显式指定 include print(df.describe(includeall)) # 会多出 city 的 count、unique、top、freq # head/tail默认 5 行可传参 print(df.head(2)) print(df.tail(2))参数说明describe(includeall)会统计所有列但数值列和类别列的指标不同输出会变宽。我一般在探索阶段先用includeall扫一眼确认没有异常值或缺失值集中出现再针对具体列做深入统计。head(n)和tail(n)的n是行数不是索引位置所以即使索引不连续也能正常取。4.2 绘图接口速查表列了方法但没提“画完不显示”的常见问题速查表里plt.hist(xs)、plt.scatter(xs, ys)、plt.plot(xs, ys)、s.hist()、s.plot()、df.plot()都列了。实际用的时候最大的坑不是方法名而是在脚本里画完图什么都没出现。原因是 Matplotlib 默认在非交互模式下不会自动显示需要显式调用plt.show()。import matplotlib.pyplot as plt import pandas as pd import numpy as np xs np.random.randn(100) ys xs * 2 np.random.randn(100) * 0.5 # 方式一pyplot 接口适合快速探索 plt.figure(figsize(8, 4)) plt.hist(xs, bins20, alpha0.7, labelxs) plt.scatter(xs, ys, s10, cred, labelys vs xs) plt.plot(xs, ys, linewidth0.5, alpha0.5) plt.legend() plt.show() # 脚本里必须加这句 # 方式二Series/DataFrame 自带 plot底层还是 matplotlib s pd.Series(xs) s.hist(bins20) plt.show() df pd.DataFrame({x: xs, y: ys}) df.plot(kindscatter, xx, yy) plt.show()参数说明bins控制直方图柱子数量太少看不出分布太多噪声大我一般从 20 开始试。alpha是透明度叠加图必调。figsize单位是英寸不是像素。df.plot()默认是折线图每个数值列一条线如果列很多会糊成一团这时候要么选特定列要么用subplotsTrue分开画。提示在 Jupyter 里用%matplotlib inline可以省掉plt.show()但在 .py 脚本里没有这个魔法命令必须手动调用。速查表没区分运行环境这是新手最容易卡住的地方之一。5. 避坑与排查速查表没写但你必须知道的五件事5.1 现象SettingWithCopyWarning警告赋值没生效原因对 DataFrame 切片后直接赋值Pandas 无法确定你改的是原数据还是副本。比如df[df[A] 1][B] 0中间经过一次布尔筛选返回的是副本赋值丢失。解决用.loc一步到位或者显式.copy()。# 错误写法可能触发警告且赋值无效 df[df[A] 1][B] 0 # 正确写法用 loc 同时指定行条件和列 df.loc[df[A] 1, B] 0 # 如果确实要操作副本先 copy subset df[df[A] 1].copy() subset[B] 05.2 现象apply返回了意料之外的类型原因函数返回值类型决定了apply的返回类型。返回标量得 Series返回 Series 得 DataFrame返回 DataFrame 得多层索引。速查表列了四种情况但没给例子。解决先拿一小段数据试跑确认返回类型再全量执行。# 返回标量得到 Series df[A].apply(lambda x: x * 2) # 返回 Series得到 DataFrame df.apply(lambda row: pd.Series([row[A] 1, row[B] 1]), axis1)5.3 现象pd.concat之后索引重复原因pd.concat([df1, df2], axis0)默认保留原索引两个 DataFrame 索引都是 0,1,2 时合并后出现重复索引。后续用loc访问会返回多行。解决加ignore_indexTrue重置索引或者合并后用reset_index(dropTrue)。df1 pd.DataFrame({A: [1, 2]}) df2 pd.DataFrame({A: [3, 4]}) # 索引重复 combined pd.concat([df1, df2], axis0) print(combined.index) # Int64Index([0, 1, 0, 1]) # 重置索引 combined pd.concat([df1, df2], axis0, ignore_indexTrue) print(combined.index) # RangeIndex(start0, stop4)5.4 现象merge之后行数变多原因连接键在任一表中不唯一导致笛卡尔积式膨胀。比如左表一个键出现 3 次右表同一个键出现 2 次合并后该键对应 6 行。解决合并前先检查键的唯一性或者用validate参数强制校验。# 检查右表键是否唯一 print(df2[key].duplicated().any()) # 强制一对一合并不满足直接报错 pd.merge(df1, df2, onkey, validateone_to_one)5.5 现象fillna之后数据类型变了原因对整数列填充 NaN 时Pandas 会把整列转成 float因为整数类型不支持 NaN。填充后即使没有缺失值类型也回不去了。解决填充后显式astype转回整数或者用 Pandas 的可空整数类型Int64。s pd.Series([1, 2, None]) print(s.dtype) # object 或 float64 s_filled s.fillna(0) print(s_filled.dtype) # float64 # 转回整数 s_filled s_filled.astype(int) print(s_filled.dtype) # int646. 把速查表用成条件反射我的三个进阶习惯速查表最大的价值不是“查得到”而是“不用查”。我用了半年之后慢慢把里面最高频的几组操作练成了条件反射这里分享三个具体习惯你可以直接抄。习惯一用pd.DataFrame.pipe串起清洗步骤。速查表没提pipe但它和apply是互补的。apply作用于数据pipe作用于整个 DataFrame适合把多个清洗函数串成流水线。比如def drop_high_nan(df, threshold0.5): return df.dropna(axis1, threshint(len(df) * (1 - threshold))) def fill_num_median(df): num_cols df.select_dtypes(includenumber).columns df[num_cols] df[num_cols].fillna(df[num_cols].median()) return df cleaned ( raw_df .pipe(drop_high_nan, threshold0.3) .pipe(fill_num_median) .reset_index(dropTrue) )这样写的好处是每一步可单独测试出问题能快速定位是哪一环。我一般把pipe链控制在 5 步以内太长就拆成两个函数。习惯二用df.select_dtypes替代手动列筛选。速查表里df.columns只列了列名但实际清洗时经常要“把所有数值列拿出来”。select_dtypes(includenumber)比手动写列名列表可靠得多尤其是列名会变的时候。num_df df.select_dtypes(includenumber) cat_df df.select_dtypes(includeobject) date_df df.select_dtypes(includedatetime)习惯三绘图前先df.plot再plt.show但保存用plt.savefig。速查表列了df.plot()但没提保存。我一般在 notebook 里用plt.show()看在脚本里用plt.savefig(output.png, dpi150, bbox_inchestight)存。dpi控制分辨率bbox_inchestight去掉多余白边。这两个参数我每次都会加不然图要么糊要么留大片空白。操作常用参数我的默认值什么时候改df.plot()kindline要看分布改hist看关系改scatterplt.savefig()dpi150打印用300网页用72df.describe()includeall只看数值列时去掉pd.concat()ignore_indexTrue需要保留原索引时设Falsedf.fillna()method不用时间序列用ffill或bfill从那以后我每次拿到新数据都强制走一遍describe(includeall)→select_dtypes分列 →pipe清洗 →plot抽检这四步基本能在十分钟内判断数据能不能直接用。这份速查表就压在我键盘底下翻得最多的还是apply返回类型和axis那两页。希望帮到你。本文还有配套的精品资源点击获取