1. 先解决"为什么":Notebook的工作哲学
1.1 传统脚本方式卡在哪
很多人第一次接触 Jupyter Notebook 时,心里都会冒出同一个疑问:我用记事本写个.py文件,再在终端里跑一遍,不也能出结果吗?为什么非要搞一个网页版的编辑器?
答案是:能出结果,但过程完全不同。拿数据分析举个例子,以前我在处理一批销售数据时,通常的流程是写一大段脚本,把数据读取、清洗、画图、分析一股脑塞进去,然后敲回车等着。运气好,一次跑通,直接看结论;运气不好,报了错,就得从头到尾逐行检查,改完再跑一遍。最难受的是,中间某个环节我想换个思路验证一下——比如把统计维度从按天换成按周——就得把整个脚本复制一份再改,改错了还要来回折腾。
这种方式在任务边界极其清晰、步骤极其固定的场景下没问题,比如定时批量处理任务。但绝大多数探索性工作根本不是这样的。你会反复调整参数、切换视角、对照中间结果,脚本的开发模式天然在这种场景下拖慢节奏。
1.2 Notebook的核心思路:交互式迭代
Jupyter Notebook 把整个分析过程拆成了一个个独立的"格子",每个格子可以单独运行、单独出结果,运行完的变量和中间数据还都保留在同一个"会话"里。这意味着你可以先读取数据,看一眼前几行,确认没问题再写清洗逻辑;清洗完画一张图,发现分布不对,再回去调整参数重新跑那一格。
这种"运行一格、看一格结果、再决定下一步"的节奏,才是数据分析真正的天然节奏。尤其是当你处理一份从来没见过的数据时,不要想着一步到位,先把数据"摸"一遍再说,而 Notebook 就是为这种工作方式设计的。
这一点的价值怎么强调都不过分。它不只是省了几分钟脚本执行时间,而是改变了你面对数据时的心态——你不再担心写错一步导致整个流程崩掉,因为每一步的中间结果都是可见、可回退、可单独修改的。这种安全感对于处理复杂数据的人来说,比任何功能都重要。
1.3 它不擅长什么:用对场景才高效
不过我也得说清楚,Notebook 不是万能的。它虽然交互体验好,但有几个明显的短板:
- 不适合大规模工程项目:几千行的代码拆成一堆格子,可读性反而下降,依赖关系也容易一团乱麻。
- 不适合纯脚本任务:比如一个部署在服务器上的定时采集脚本,写成 Notebook 就是个累赘。
- 对版本控制不友好:
.ipynb文件本质是 JSON 格式,多人协作时 git 合并冲突会让人头大。好在后来有 jupytext 这类工具把 Notebook 转成纯文本处理,但这是后话。
我的建议是:凡是以"探索、分析、演示"为主要目标的 Python 工作,用 Notebook;凡是以"稳定、批量、自动化"为目标的工作,写脚本。两者搭配,才是完整的工作流。
2. 安装与环境准备:选对Python环境比装软件更重要
2.1 最简单的安装路径:pip安装
书接上文,安装是很多人容易草率处理的一步。我的建议是不要一上来就在系统全局环境里乱装,否则过不了两个月,各种包的版本冲突能让你的 Python 环境彻底瘫痪。
如果你的电脑里已经装了 Python(建议 3.8 以上版本),那么最简单的安装方式是在终端里执行:
pip install notebook装完之后,输入:
jupyter notebook看到终端输出一串网址(通常是http://localhost:8888/tree)并自动弹出浏览器页面,就算安装成功了。
但这里有个前提条件没解决:你当前工作的 Python 环境到底是什么状态?如果你平时用 pip 装过很多包,全局环境里可能已经乱成一锅粥了。所以我强烈建议你从第一步就养成用虚拟环境的习惯。
2.2 用conda创建干净的分析环境
虚拟环境这个词听起来很高级,其实核心就一句话:给不同的项目单独隔离一套 Python 环境,A 项目里装的包不影响 B 项目。装包的时候不会把世界搞得一团糟。
比较省事的方式是安装 conda(一个开源的包管理与环境管理工具),然后用它创建环境:
conda create -n>python -m venv myenv source myenv/bin/activate # Windows 下是 myenv\Scripts\activate pip install notebook无论用哪种方式,核心原则一样:环境隔离,环境专一。多年以后你会感谢自己当时没偷懒。
2.3 启动与验证:从终端到浏览器
环境准备好之后,启动就简单了。激活环境,运行jupyter notebook,浏览器会自动打开 Dashboard 界面。如果你是在服务器上使用,则需要手动复制终端里给出的带 token 的地址到本地浏览器,这个在远程工作时很常用,后面我会单独说明。
启动之后建议先做两步验证:
- 新建一个 Notebook(右侧的 New 按钮 → Python 3),确认能正常进入编辑页。
- 在第一个单元格里输入下面这行经典代码,按 Shift + Enter 运行:
import sys print(sys.version)如果正确输出了 Python 版本号,说明环境和内核都通了。
注意:
jupyter notebook命令会占据这个终端窗口,它是前端服务器进程。想让它后台运行,可以后续配置 jupyter server,但日常单机使用不需要太操心。
2.4 初始化配置:密码与远程访问
如果你只在本地自己用,跳过这一节没问题。但如果你在服务器上跑数据分析,需要在浏览器里远程访问 Notebook,那一定要做这一步,否则你的 Jupyter 服务相当于裸奔——任何能访问你服务器端口的人都能直接操作你的内核。
生成配置文件:
jupyter notebook --generate-config然后在生成的jupyter_notebook_config.py中设置访问密码。最简单的方式是先进入 Python 交互环境,用notebook.auth模块生成密码串:
from notebook.auth import passwd passwd()按提示输入两次密码,会得到一串以argon2开头的密文字符串,把它填进配置文件的c.NotebookApp.password字段即可。
远程访问还需注意两个问题:
- 建议改用
jupyter server方式,并配置 HTTPS,避免密码在网络上明文传输。 - 防火墙和端口映射要手动放行 8888 端口,否则浏览器根本连不上。
这些属于进阶运维内容,先了解存在这么一回事,等真正需要时再深入研究。
3. 界面地图:菜单、工具栏和单元格区
3.1 Dashboard界面:一切从这里开始
启动完成后,你首先看到的是 Jupyter 的文件管理页,官方叫 Dashboard。这里展示当前工作目录下的所有文件和文件夹。很多人忽略了一个关键动作:启动 Jupyter 时所在的目录,就是 Dashboard 的根目录。
也就是说,如果你在某个项目文件夹里执行jupyter notebook,Dashboard 就会显示这个文件夹的内容。把项目相关的数据文件、代码文件都放在同一个目录下,后续读取数据时的路径问题会少很多。
在 Dashboard 右上角的 New 菜单里,可以新建 Notebook、Python 文件、文本文件、文件夹等。建议你从第一个项目开始就建立清晰的目录结构,比如:
project/ ├── notebooks/ # 存放 ipynb 文件 ├── data/ # 存放数据文件 └── output/ # 存放导出结果3.2 编辑页的四大区域
点击新建的 Notebook,进入编辑页。这一页从结构上可以拆成四大区域:
- 顶部菜单栏:File、Edit、View、Insert、Cell、Kernel、Widgets、Help 等一系列下拉菜单。
- 工具栏:常用操作的快捷按钮,比如新建、剪切、复制、运行、中断内核、重启内核。
- 单元格区:正文核心区域,所有代码和文字都在这些格子里。
- 内核状态指示:右上角一个圆点,灰色表示内核空闲,实心黑圆点表示内核正在运行,圆点空心表示忙碌中。
菜单栏里真正高频使用的只有几个:File 里的 Save and Export、 Download as(导出为 py、html、md 等格式);Cell 里的 Run All、Run All Above、Current Outputs 清理;Kernel 里的 Restart & Run All。其他的菜单点得很少,可以慢慢熟悉,不需要一开始就全记住。
3.3 内核(Kernel)到底是什么
内核这个问题,很多人用了很久也没搞明白,但它其实是 Notebook 一切行为的底层逻辑。
所谓内核,就是一个一直挂在后台的 Python 进程。你在单元格里写的代码,并不是浏览器帮你执行的,而是被发送到这个 Python 进程里执行的,执行完的结果再回传给浏览器显示。
这个机制说明了很多重要问题:
- 变量持久化:A 单元格里定义了变量,B 单元格里可以用,因为它们是同一个进程里的同一个命名空间。
- 状态不干净:如果某个单元格运行出错,不代表之前的变量没了,也不代表环境被"重置"了。恰恰相反,出错前定义的变量都会保留,这既是好事也是隐患。
- 重启内核 = 失忆:Kernel 菜单里的 Restart,相当于把整个 Python 进程关掉重开,所有变量清零,重新开始。
我记得有一次在某课程作业里,明明在笔记本的中间某格定义过一个 DataFrame,但运行后面某个格子时还是报"变量不存在"的错误。我找了半天才发现,中间某次手动中断了内核、重新执行时漏掉了定义变量那一格。这种情况在实战中太常见了,所以当你怀疑"怎么变量不见了"时,第一反应应该是:内核是不是被重启过?
4. 单元格机制深度拆解:两种细胞与运行逻辑
4.1 代码单元格与Markdown单元格
在 Jupyter 里,一切内容都装在单元格里。这些单元格按类型可以粗分为两种:代码单元格和 Markdown 单元格。
代码单元格就是执行 Python 代码的地方。它的特殊之处在于:执行过后,单元格下方会出现输出区,用来展示代码的执行结果,可能是文本、表格、图片,也可能是交互式部件。输出区的内容与代码本身一起,构成了一份完整的分析记录。
Markdown 单元格则是用来写说明文字的。它支持 Markdown 语法,也支持 LaTeX 数学公式。比如:
# 一级标题 **加粗文字** $E=mc^2$写完按运行,这段 Markdown 文本就渲染成漂亮的排版结果,肉眼看见的是渲染后的样式,而不是源码。这个功能是 Notebook 作为"可交互文档"的关键:你的分析过程和结论说明可以写在同一个文件里,代码旁边就是解释,读起来像一份带逻辑脉络的笔记,而不是一份冷冰冰的脚本。
4.2 模式切换与运行方式
这里必须说一个新手最容易搞晕的概念:单元格有"选中状态",另一个是"编辑状态"。
- 选中状态(命令模式):单元格周围会有蓝色边框,此时整个格子作为一个整体存在,按上下方向键可以在不同单元格之间移动,按
文件操作可以删除、复制等。 - 编辑状态(编辑模式):单元格周围是绿色边框,此时光标在格子里,可以直接输入代码或文字。按 Esc 退出编辑模式,回到命令模式。
运行单元格的快捷键也需要一次性记住:
- Shift + Enter:运行当前单元格,并让光标移动到下一个单元格。
- Ctrl + Enter:只运行当前单元格,光标不动。
- Alt + Enter:运行当前单元格,并在下方新建一个单元格。
绝大多数人最常用的其实是 Shift + Enter,因为"运行完顺手就跳到下一个格子"这种节奏,非常贴合从上到下的分析流程。
对于有好多格的 Notebook,还想批量执行整篇代码,别忘了工具栏上的 Run All 按钮,或者用菜单里的 Cell → Run All。它会按从上到下的顺序,把每个代码格依次运行一遍,输出结果全部刷新。刚才我提到过,Markdown 单元格也会在这个过程被渲染。
4.3 共享命名空间:Notebook最容易被忽略的坑
某次处理某个数据集的缺失值时,我在代码格 A 里把清洗后的 DataFrame 赋给变量df_clean,然后在后面十几个格里连续画图、统计,一切正常。结果第二天打开 Notebook 继续做,直接运行后面的格子,报错说df_clean未定义。
这种错误在 Noteboook 里发生频率非常高,根源就是"共享命名空间"这个机制:Notebook 从上往下运行单元格,但它并不保证你一定会从上往下把所有格都运行一遍。
假如你直接跑到后面的格子,前面的格子没执行过,变量自然不存在。而不巧的是,绝大多数变量在前一轮会话里都被创建过,所以你很难意识到问题出在"前面的格子没跑",只看到"变量没了"。
这个坑的解决方案也是五花八门。比较务实的做法是:
- 在 Notebook 开头放一个"初始化单元格",把数据读取、导入、全局配置都集中在那里。之后凡是"变量不存在"的报错,先让这个单元格重新跑一遍。
- 分析工作完成后,养成一个习惯:
Kernel → Restart & Run All,把整篇文章从头到尾跑通一遍再交付。这既是自测,也方便别人复现你的结果。
这条经验是我踩过不少坑才总结出来的。在一次项目汇报时我就是没跑初始化单元格,直接先往下运行,导致展示现场报错,体验很尴尬。从那以后,"先 Restart & Run All 一遍再汇报"就成了我的铁律。
5. 快捷键体系:让操作成为肌肉记忆
5.1 命令模式与编辑模式
讲完了单元格机制,接下来必须说说快捷键。很多人觉得快捷键学起来费劲,但在 Jupyter 里,快捷键不是锦上添花的小技巧,而是直接影响流畅度的关键。原因在于 Notebook 的界面写代码和看文本混在一起,鼠标操作和键盘操作的来回切换很容易打断思路。
前面提到,Notebook 有两种模式,所有快捷键都围绕这两种模式展开。先记住一个切换口诀:
Esc退出编辑状态,回到命令模式。Enter在选中的单元格上进入编辑状态。
只要记住这两个键,其他快捷键就不会搞混了。
5.2 命令模式核心快捷键
命令模式下,键盘操作的字母按键都有各自的作用,高频的几个如下:
| 快捷键 | 功能 |
|---|---|
| A / B | 在当前单元格上方/下方新建一个单元格 |
| D + D | 连续按两次 D,快速删除当前单元格 |
| M | 把当前单元格变成 Markdown 单元格 |
| Y | 把当前单元格变成代码单元格 |
| Up / Down | 在当前单元格之间上下移动 |
| Shift + Up / Down | 向上/向下选中多个单元格,用于合并或批量操作 |
| Shift + J / K | 批量选中从上到下/从下到上的单元格并向下扩展选择 |
| C / X / V | 复制、剪切、粘贴选中的单元格 |
| Z | 撤销单元格删除 |
| S | 保存 Notebook |
| Ctrl + S | 同样是保存(编辑模式也可用) |
| Shift + L | 显示或隐藏行号,排查代码行号时非常有用 |
| Space / Shift + Space | 向下 / 向上翻页,在长文档里快速滚动 |
这里最值得单独说的是 D + D。删除单元格是个高频操作,但很多人不知道这个快捷键,用鼠标右键菜单删,效率非常低。
5.3 编辑模式与代码补全
编辑模式下,快捷键更多是跟代码编写相关的操作:
- Tab:代码补全或缩进。输入
pd.后按 Tab,会弹出 pandas 的所有方法;继续输入几个字符再按 Tab,会自动过滤出你想要的函数名。 - Shift + Tab:显示当前对象的文档字符串(docstring)。把鼠标放在一个函数名里调用,按 Shift + Tab 会看到参数说明和简要用法。涉及陌生库时这个方法比翻文档快得多。
- Ctrl + /:整行注释或取消注释,多行代码需要临时屏蔽时效率极高。
- Ctrl + Shift + -:在光标当前位置把所在行拆成两行(相当于光标处分行)。
- Ctrl + `:打开命令行面板,类似于很多现代编辑器里的统一命令入口,输入命令可以直接执行。
代码补全这一块,因为 Jupyter 自带的内置补全逻辑比较简单,你会发现它对比较复杂的模块方法支持得不算好,一些符号和方法甚至补不出来。我自己在数据分析实战中,大量时间其实都是和 pandas 的 DataFrame 打交道,靠纯手打 DataFrame 几百个方法是完全不现实的。所以如果你想要更智能的补全,后面可以安装一些扩展工具来增强,这个我在后续的(下)篇里细说。
6. 魔法命令:普通编辑器给不了的超能力
6.1 行魔法与单元格魔法
学习 Jupyter Notebook 如果只看界面和快捷键,那只能说还停留在普通编辑器的水平。真正让它强大的,是一套叫"魔法命令"(Magic Commands)的特殊语法。魔法命令不是 Python 语法的一部分,而是 Jupyter 内核提供的扩展指令,用于处理代码执行过程中那些 Python 本身做不到的事。
魔法命令分两种:
- 行魔法(Line Magic):作用于一行,以单个
%开头。 - 单元格魔法(Cell Magic):作用于整个单元格,以两个
%%开头。
我最常用的魔法命令是%timeit。以前写优化代码的时候,想测一测两个算法谁的耗时更短,直接把%timeit放在代码前面,它就会自动运行多次并给出统计结果,比手动time模块方便太多了。
%timeit pd.merge(df_left, df_right, on='key')输出类似这样:
35.7 ms ± 2.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)%%timeit则可以作用于整个格子里的所有代码。比如你想测试一段包含多行的数据预处理流程的整体耗时,把%%timeit放在单元格第一行,后面所有代码都会参与计时。它会把整段代码按一次迭代为单位来执行,并给出平均耗时和波动范围,这对性能评估非常有用。
6.2 常用行魔法实测
除了%timeit,还有几个行魔法值得掌握:
%run:在一个 Notebook 里直接运行另一个 Python 文件。
%run myscript.py这比用!python myscript.py的意义更大——%run会把脚本里的代码运行在当前内核进程里,脚本定义的所有函数和变量都能在当前会话中直接使用,而不只是"执行完就结束"。
%load:把外部文件内容加载到当前单元格里。比如你有一个别人写的脚本template.py,想研究它的逻辑,直接输入%load template.py,运行后,文件内容会填充到当前单元格里,随后你就能看到代码本身。这个命令对学习别人的代码特别方便。
%env:查看或设置环境变量。
%env MY_VAR=hello %env MY_VAR第二个%env会输出变量的值。在 Notebook 里临时设置环境变量,比去 shell 里改配置文件快很多。
%matplotlib inline:在使用 matplotlib 画图时,这个命令必不可少。它的作用是把 matplotlib 生成的图像直接嵌入到 Notebook 的输出区里显示,而不是弹出另一个窗口。在 Jupyter 里画图,几乎每个项目开头都会执行一句:
%matplotlib inline import matplotlib.pyplot as plt%pwd和%ls:这两个和终端里的 pwd、ls 意思差不多,分别显示当前工作目录和目录下的文件。为什么值得记住?因为不少人刚使用 Notebook 时老是困惑"我的文件到底在哪个目录下""为什么读不到文件",%pwd一敲就能确认位置。
6.3 单元格魔法示例
单元格魔法里,除了%%timeit,还有几个实战场景很常用的。
%%bash:在单元格里直接写 shell 命令。比如你在处理 CSV 时想知道文件大小、行数,或者想用 grep 快速过滤日志文件,这些操作在 Notebook 里可以直接这样写:
%%bash wc -l data.csv head -5 data.csv这个单元格会被一个独立的 bash 进程执行,而且它的执行环境和 Notebook 的 Python 进程没有命名空间上的牵扯。
%%html和%%markdown:在单元格里直接写 HTML 或 Markdown 源代码并渲染出来。比如你需要在 Notebook 里嵌入一段带样式的提示框,或者做一个漂亮的列表,用这两个命令比新建一个 Markdown 单元格要灵活。
%%writefile:把整个单元格的内容直接写入文件。比如你想生成一份 Python 脚本或配置文件,把内容写在一个单元格里,第一行写%%writefile data_clean.py,运行后文件就落盘了,免去从 Notebook 复制代码再粘贴到文本编辑器的麻烦。
6.4 查看帮助与自定义魔法
魔法命令这么多,记不全很正常。好在 Jupyter 提供了快速查阅的方法:
%magic运行后,会列出当前内核支持的所有魔法命令及简要说明,相当于一本随身手册。
如果你需要的是某个具体魔法命令的详细使用说明,用?就行:
%timeit?运行后会在下方弹出一个帮助窗格,展示该魔法的完整参数列表和示例。
还有一点:魔法命令是可以用%automagic来省略的——开启后,不写%前缀也能直接使用部分魔法命令。比如timeit ...会被自动识别为%timeit ...。不过我个人不太推荐开启这项功能,容易造成语法的歧义。
关于自定义魔法命令,这里先说个方向:Jupyter 允许用户通过函数定义自己的行魔法或单元格魔法。例如,你可以注册一个叫%greet的命令,在单元格开头输出一句问候语,并接收参数。这类自定义魔法命令在团队内部封装常用操作时非常实用。因为内容比较多,我会留到(下)篇里专门介绍,包括怎么注册、怎么传参、怎么让它在多台机器上复用。
在写下这篇(上)的过程中,我脑子里反复出现一个画面:当年第一次接触 Notebook 时,对着空白的单元格完全不知道从哪里开始。如果当时的我能看到一份像本文这样、把"为什么要用"和"怎么用好"讲清楚的资料,可能会少走好多弯路。工具这种东西,花半小时摸清机制,后面每一天的效率都在回本。下一篇(下)我打算重点聊聊内核细节、Notebook 与文件系统的边界问题、自定义魔法命令和扩展配置,这些都是进阶玩法,到时候见。