Jupyter-Notebook操作集锦

  |  

摘要: Jupyter Notebook 的基础知识和操作集锦

【对算法,数学,计算机感兴趣的同学,欢迎关注我哈,阅读更多原创文章】
我的网站:潮汐朝夕的生活实验室
我的公众号:算法题刷刷
我的知乎:潮汐朝夕
我的github:FennelDumplings
我的leetcode:FennelDumplings


Jupyter 基础

Jupyter 项目中的主要组件就是 notebook,这是一种交互式的文档类型,可以用于编写代码、文本(可以带标记)、数据可视化以及其他输出。Jupyter notebook 与内核交互,内核是编程语言的交互式计算协议的实现。Python 的 Jupyter 内核使用 IPython 系统进行内部活动。

Jupyter Notebook 架构示意图:


Jupyter 快捷键

显示对象信息

显示变量 a 的信息

1
a?

显示函数 b 的源代码

1
b??

显示所有匹配通配符的命名

1
np.*load*?

Jupyter 魔法命令

IPython 提供了许多魔法命令。魔法命令都以 %%% 开头,以 % 开头的为行命令,以 %% 开头的为单元命令。

行命令只对命令所在的行有效,而单元命令则必须出现在单元的第一行,对整个单元的代码进行处理。

查看命令说明

1
%magic

扩展库可以提供自己的魔法命令,这些命令可以通过 %load_ext 载入。

例如 %load_ext cython 载入 %%cython 命令,以该命令开头的单元将调用 Cython 编译其中的代码。

(0) 常用魔法命令汇总

命令 描述
%quickref 显示快速参考
%magic 显示所有可用魔术命令详细文档
%debug 从最后发生报错的底部进入交互式调试器
%hist 打印命令输入/输出历史
%pdb 出现任意报错后进入调试器
%paste 从剪贴板中执行已经预先格式化的 Python 代码
%cpaste 打开一个特殊提示符,手动粘贴待执行的 Python 代码
%reset 删除交互式命名空间中所有的变量/名称
%page OBJECT 通过分页器更美观地打印显示一个对象
%run script.py 在 IPython 中运行一个 Python 脚本
%prun statement 用 cProfile 执行语句并报告输出
%time statement 运行单个语句计算时间
%timeit statement 多次运行单个语句计算平均时间
%who, %who_ls, %whos 根据不同级别的信息/详细程度,展示交互命名空间中定义的变量
%xdel variable 在 IPython 内部删除一个变量,清除相关引用

(1) 显示图表

%matplotlib 命令可以将 matplotlib 的图表直接嵌入到 Notebook 中,后面跟一个参数表示显示方式。

  • inline 表示将图表嵌入到 Notebook 中。
1
%matplotlib inline

内嵌图表的输出格式默认为 PNG,可以通过 %config 命令修改这个配置。

%config 命令可以配置 IPython 中的各可配置对象,其中 InlineBackend 对象为 matplotlib 输出内嵌图表时所使用的配置,我们配置它的 figure_format=”svg”,这样可将内嵌图表的输出格式修改为 SVG。

1
%config InlineBackend.figure_format="svg"
  • qt4 表示使用 QT4 界面库显示图表

可以将图表输出模式修改为使用 GUI 界面库,下面的 qt4 表示使用 QT4 界面库显示图表。需要根据自己系统的配置,选择合适的界面库:gtk、osx、qt、qt4、tk、wx。

1
%matplotlib qt4

(2) 性能分析

%timeit

%timeit 调用 timeit 模块对单行语句重复执行多次,计算出执行时间。

1
2
a = [1, 2, 3]
%timeit a[1] = 10

%%timeit

%%timeit 用于测试整个单元中代码的执行时间。下面的代码测试空列表中循环添加 10 个元素所需的时间:

1
2
3
4
%%timeit
vec = []
for i in range(10):
vec.append(i)

%%capture

time 和 timeit 命令都使用 print 输出信息,如果希望用程序分析这些信息,可以使用 %%capture 命令,将单元格的输出保存为一个对象。

下面的程序对不同长度的列表调用 random.shuffle() 以打乱顺序,用 %time 记录下 shuffle() 的运行时间:

1
2
3
4
5
6
7
8
9
10
%%capture time_results

import random

for n in [1000, 5000, 10000, 50000, 100000, 500000]:
print("n={}".format(n))
alist = list(range(n))
%time random.shuffle(alist)

print(time_results)

time_results.stdout 属性保存标准输出管道中的输出信息:

1
print(time_results.stdout)

%timeit -o

如果在调用 %timeit 命令时添加 -o 参数,则返回一个表示运行时间信息的对象。

下面的程序对不同长度的列表调用 sorted() 排序,并使用 %timeit 命令统计排序所需的时间:

1
2
3
4
5
timeit_results = []
for n in [1000, 5000, 10000, 50000, 100000, 500000]:
alist = [random.random() for i in range(n)]
res = %timeit -o sorted(alist)
timeit_results.append((n, res))

%%prun

%%prun 调用 profile 模块,对单元中的代码进行性能分析。

(3) 代码调试

%debug 命令用于调试代码,它有两种用法:

  1. 在执行代码之前设置断点进行调试
  2. 在代码抛出异常之后,执行 %debug 命令查看调用堆栈。此时可以使用 pdb 模块提供的调试命令。

如果是先设置断点的化,需要指定文件名和行号,不太方便。

(4) 自定义魔法命令

使用 register_line_magicregister_cell_magic 装饰器可以将函数转换为魔法命令。

例子1: 使用 register_line_magic 定义行魔法命令 %find

%find 在指定的对象中搜索与目标匹配的属性名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from IPython.core.magic import register_line_magic

@register_line_magic
def find(line):
from IPython.core.getipython import get_ipython
from fnmatch import fnmatch

items = line.split()
patterns, target = items[:-1], items[-1]
ipython = get_ipython()
names = dir(ipython.ev(target))

results = []
for pattern in patterns:
for name in names:
if fnmatch(name, pattern):
results.append(name)
return results

其中

  • get_ipython() 函数获得表示 IPython 运算核的对象,通过该对象可以操作运算核。
  • 调用运算核的 ev() 方法对表达式 target 求值以得到实际的对象。

下面用自定义的 %find 命令在 numpy 模块中搜索所有以 array 开头或包含 mul 的属性名

1
2
3
4
import numpy as np

names = %find array* *mul* np
print(names)

例子2: 用 register_cell_magic 注册 %%cut 单元命令

我们经常会添加 print 语句以输出中间结果。但如果输出的字符串太多,会导致浏览器的速度变慢甚至失去响应。此时可以使用 %%cut 限制程序输出的行数和字符数。

cut() 函数有两个参数:line 和 cell,其中

  • line 为单元第一行中除了魔法命令之外的字符串,通常为魔法命令的参数
  • cell 为除了单元中第一行之外的所有字符串,为需要执行的代码。

IPython 提供了基于装饰器的参数分析函数。下面的例子使用 argument() 声明了两个参数 -l 和 -c,它们分别指定最大行数和最大字符数,它们的默认值分别为 100 和 10000。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from IPython.core.magic import register_cell_magic
from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring

@magic_arguments()
@argument("-l", "--lines", help="max lines", type=int, default=100)
@argument("-c", "--chars", help="max chars", type=int, default=10000)
@register_cell_magic
def cut(line, cell):
from IPython.core.getipython import get_ipython
from sys import stdout
args = parse_argstring(cut, line)
max_lines = args.lines
max_chars = args.chars

counters = dict(chars=0, lines=0)

def write(string):
counters["lines"] += string.count("\n")
counters["chars"] += len(string)
if counters["lines"] >= max_lines:
raise IOError( "Too Many lines" )
elif counters["chars"] >= max_chars:
raise IOError( "Too Many chars" )
else:
old_write(string)

try:
old_write, stdout.write = stdout.write, write
ipython = get_ipython()
ipython.run_cell(cell)
finally:
del stdout.write

要点如下

  • parse_argstring()` 分析行参数,第一个参数是使用 argument 装饰器修饰过的魔法命令参数,第二个参数是行命令字符串
  • 在调用单元代码之前,将 stdout.write() 替换为限制输出行数和字符数的 write() 函数
  • 调用运算核对象的 run_cell() 来运行单元代码。
  • 运行完毕之后将 stdout.write() 删除,恢复到原始状态。

下面用自定义的 %%cut 限制输出行数

1
2
3
4
%%cut -l 5

for i in range(10000):
print("line: {}".format(i))

(5) 运行任意的 Python 文件

文件中定义的所有变量(导入的、函数中的、全局定义的)在运行后,可以在IPython命令行中使用(除非出现某种异常)。

1
%run script.py

运行的脚本如果要用 IPython 命名空间中已有的变量,需要加上 -i 选项。

1
%run -i script.py

(6) 导入代码单元

1
%load script.py

Jupyter Notebook 的显示系统

display 模块

由于 Notebook 采用浏览器作为界面,因此除了可以显示文本之外,还可以显示图像、动画、HTML 等多种形式的数据。有关显示方面的功能均在 IPython.display 模块中定义。

IPython.display 模块提供的用于显示各种数据格式的类如下表

类名 说明
Audio 将二进制数据、文件、网址显示为播放声音的控件
FileLink 将文件夹路径显示为一个超链接
FileLinks 将文件夹路径显示为一组超链接
HTML 将字符串、文件或网址显示为 HTML
Image 将表示图像的二进制字符串、文件或网址显示为图像
Javascript 将字符串作为 Javascript 代码在浏览器中运行
Latex 将字符串作为 LaTeX 代买显示,主要用于显示数学公式
SVG 将字符串、文件或网址显示为 SVG 图形

当对单元中的最后一行求值并得到上述类型的对象时,将在单元的输出栏中显示对应的格式。

也可以使用 display 模块中的 display() 函数在程序中输出这些对象。

例子: 显示数学公式

1
2
3
4
5
6
from IPython import display

for i in range(2, 4):
display.display(display.Latex("$x^{i} + y^{i}$".format(i=i)))

display.Latex("$x^4 + y^4$")

例子: 显示 URL 图像

1
2
3
url = "http://39.105.154.142:8080/download/images/24.jpeg"

display.Image(url=url, embed=True)

例子: 显示 Numpy 数组

将数组转换成 png 格式的字符串数据。然后通过 Image 将图像数据嵌入到 Notebook。

1
2
3
4
5
6
7
8
9
10
def as_png(img, **kw):
"""
将数组转换成 PNG 格式的字符串数据
"""
import io
from matplotlib import image
from IPython import display
buf = io.BytesIO()
image.imsave(buf, img, **kw)
return buf.getvalue()

下面通过公式 $\sin(x^{2} + 2y^{2} + xy)$ 生成二维数组 z,并调用 as_png 转换为字符串 png。先查看该字符串的前 10 个字节,然后用 Image 将字符串显示出来。

1
2
3
4
5
6
7
import numpy as np

y, x = np.mgrid[-3:3:300j, -6:6:600j]
z = np.sin(x ** 2 + 2 * y ** 2, + x * y)
png = as_png(z, cmap="Blues", vmin=-2, vmax=2)
print(repr(png[:10]))
display.Image(png)

自定义对象的显示格式

有两种方式自定义对象在 Notebook 中的显示格式

  • 给类添加相应的显示方法
  • 为类注册相应的显示函数

给类添加相应的显示方法

根据需要自定义下面的函数即可。

1
2
3
4
5
_repr_html_()
_repr_svg_()
_repr_javascript_()
_repr_latex_()
_repr_png_()

然后在使用的时候对应的使用下面的函数即可,其中 c 是定义了上述函数的类的对象。

1
2
3
4
5
display.display_png(c)
display.display_html(c)
display.display_latex(c)
display.display_javascript(c)
display.display_svg(c)

例子: 显示颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Color(object):
def __init__(self, r, g, b):
self.rgb = r, g, b

def html_color(self):
return "#{:02x}{:02x}{:02x}".format(*self.rgb)

def invert(self):
r, g, b = self.rgb
return Color(255 - r, 255 - g, 255 - b)

def _repr_html_(self):
color = self.html_color()
inv_color = self.invert().html_color()

template = "<span style=\"background-color:{c};color:{ic};padding:5px;\">{c}</span>"
return template.format(c=color, ic=inv_color)

def _repr_png_(self):
img = np.empty((50, 50, 3), dtype=np.uint8)
img[:,:,:] = self.rgb
return as_png(img)

c = Color(255, 10, 10)
c

display.display_png(c)
display.display_html(c)

为类注册相应的显示函数

每种输出格式都对应一个 Formatter 对象,它们被保存在 DisplayFormatter 对象的 formatters 字典中,下面获取该字典中与 PNG 格式对应的 Formatter 对象。

1
2
shell = get_ipython()
png_formatter = shell.display_formatter.formatters["image/png"]

调用 Formatter.for_type_by_name() 可以为该输出格式添加指定的格式显示函数,其前两个参数分别为模块名和类名

由于使用字符串指定类,因此添加格式显示函数时不需要载入目标类。

如果目标类已经载入,可以使用 for_type() 方法为其添加格式显示函数。

例子: 为 Numpy 的数组添加显示函数 as_png

1
2
3
4
5
png_formatter.for_type_by_name("numpy", "ndarray", as_png)

y, x = np.mgrid[-3:3:300j, -6:6:600j]
z = np.sin(x ** 2 + 2 * y ** 2, + x * y)
z

例子: 将表示分数的 Fraction 类用 LaTeX 显示

1
2
3
4
5
6
7
8
9
10
11
from fractions import Fraction

shell = get_ipython()
latex_formatter = shell.display_formatter.formatters["text/latex"]

def fraction_formatter(obj):
return "$$\\frac{}{}$$".format(obj.numerator, obj.denominator)

latex_formatter.for_type(Fraction, fraction_formatter)

Fraction(3, 4) ** 4 / 3

定制 Jupyter Notebook

Notebook 系统由浏览器、服务器和运算核三部分组成。这三部分都是可以定制的。

用户配置

输出当前的配置文件夹的路径。

1
2
3
4
import os
ipython = get_ipython()
print("HOME 环境变量: {}".format(os.environ["HOME"]))
print("IPython 配置文件夹: {}".format(ipython.ipython_dir))

服务器和浏览器扩展插件

.ipython 文件夹之下还有两个子文件夹,extensionsnbextensions,它们分别用于保存服务器和浏览器的扩展程序。

  • extensions:存放用 Python 编写的服务器扩展程序。
  • nbextensions:存放 Notebook 客户端的扩展程序,通常为 JavaScript 和 CSS 样式表文件。

Notebook 的服务器基于 tornado 服务器框架开发,因此编写服务器的扩展程序需要了解 tornado 框架,而开发 Notebook 客户端(浏览器的界面部分)的扩展程序则需要了解 HTML、JavaScript 和 CSS 样式表等方面的内容。

添加新的运算核

执行用户代码的运算核与 Notebook 服务器是独立的进程。因此可以添加新的运算核,甚至是不同语言的。

Jupyter 的目标是创建通用的科学计算的开发环境,支持 Julia、Python、PyPy、NodeJS 和 R 等在数据处理领域流行的语言。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import os
import json

ipython = get_ipython()
kernels_folder = os.path.join(ipython.ipython_dir, "kernels")

if not os.path.exists(kernels_folder):
os.mkdir(kernels_folder)

python3_path = "/home/ppp/anaconda3/envs/rl/bin/python"
kernel_settings = {"argv": [python3_path, "-m", "IPython.kernel", "-f", "{connection_file}"]
,"display_name": "Python3-rl"
,"language": "python"
}

kernel_folder = os.path.join(kernels_folder
,kernel_settings["display_name"]
)
if not os.path.exists(kernel_folder):
os.mkdir(kernel_folder)

kernel_fn = os.path.join(kernel_folder, "kernel.json")

with open(kernel_fn, "w") as f:
json.dump(kernel_settings, f, indent=4)

上面的代码创建 .ipython\kernels\python3-64bit\kernel.json 文件,它是一个 JSON 格式的字典,其中 “argv” 键为运算核的启动命令,”display_name” 为运算核的显示名称,”language” 为运算核的语言。

刷新 Notebook 之后,可以在 New 下拉菜单中找到 “Python3-rl” 选项。


操作集锦


Share