Jupyter Notebook详细教程(下)

实例分析

现在我们已经看了一个 Jupyter Notebook,是时候看看它们在实践中使用了,这应该会让你更清楚地了解它们为什么那么受欢迎。现在是时候开始使用前面提到的财富 500 数据集了。请记住,我们的目标是了解美国最大公司的利润在历史上是如何变化的。

值得注意的是,每个人都会有自己的喜好和风格,但是一般原则仍然适用,如果你愿意,你可以在自己的 notebook 上跟随这一段,这也给了你自由发挥空间。

命名你的 notebook

在开始编写项目之前,你可能想要给它一个有意义的名称。也许有点让人困惑,你不能从 Notebook 的应用程序中命名或重命名你的 notebook,而必须使用仪表盘或你的文件浏览器来重命名 .ipynb 文件。我们将返回到仪表板,以重命名你之前创建的文件,它将有默认的 notebook 的文件名是 Untitled.ipynb

你不能在 notebook 运行时重命名它,所以你首先要关闭它。最简单的方法就是从 notebook 菜单中选择 “File > Close and Halt”。但是,您也可以通过在笔记本应用程序内 “Kernel > Shutdown” 或在仪表板中选择 notebook 并点击 “Shutdown” (见下图)来关闭内核。

然后你可以选择你的 notebook,并在仪表板控件中点击 “Rename”。

注意,在你的浏览器中关闭笔记的标签页将不会像在传统的应用程序中关闭文档的方式一样关闭你的 notebook。notebook 的内核将继续在后台运行,需要在真正“关闭”之前停止运行 —— 不过如果你不小心关掉了你的标签或浏览器,这就很方便了!如果内核被关闭,你可以关闭该选项卡,而不用担心它是否还在运行。

如果你给你的 notebook 起了名字,打开它,我们就可以开始实践了。

设置

通常一开始就使用一个专门用于导入和设置的代码单元,因此如果你选择添加或更改任何内容,你可以简单地编辑和重新运行该单元,而不会产生任何副作用。

%matplotlib inline

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

sns.set(style="darkgrid")

我们导入 pandas 来处理我们的数据,Matplotlib 绘制图表,Seaborn 使我们的图表更美。导入 NumPy 也是很常见的,但是在这种情况下,虽然我们使用的是 pandas,但我们不需要显式地使用它。第一行不是 Python 命令,而是使用一种叫做行魔法的东西来指示 Jupyter 捕获 Matplotlib 图并在单元输出中呈现它们;这是超出本文范围的一系列高级特性之一。

让我们来加载数据。

df = pd.read_csv('fortune500.csv')

在单个单元格中这样做也是明智的,因为我们需要在任何时候重新加载它。

保存和检查点

现在我们已经开始了,最好的做法是定期存储。按 Ctrl + S 键可以通过调用“保存和检查点”命令来保存你的 notebook,但是这个检查点又是什么呢?

每当你创建一个新的 notebook 时,都会创建一个检查点文件以及你的 notebook 文件;它将位于你保存位置的隐藏子目录中称作 .ipynb_checkpoints,也是一个 .ipynb 文件。默认情况下,Jupyter 将每隔 120 秒自动保存你的 notebook,而不会改变你的主 notebook 文件。当你“保存和检查点”时,notebook 和检查点文件都将被更新。因此,检查点使你能够在发生意外事件时恢复未保存的工作。你可以通过 “File > Revert to Checkpoint“ 从菜单恢复到检查点。

调查我们的数据集

我们正在稳步前进!我们的笔记已经被安全保存,我们将数据集 df 加载到最常用的 pandas 数据结构中,这被称为 DataFrame ,看起来就像一张表格。那我们的数据集会是怎样的?

df.head()
Year Rank Company Revenue (in millions) Profit (in millions)
0 1955 1 General Motors 9823.5 806
1 1955 2 Exxon Mobil 5661.4 584.8
2 1955 3 U.S. Steel 3250.4 195.4
3 1955 4 General Electric 2959.1 212.6
4 1955 5 Esmark 2510.8 19.1
df.tail()
Year Rank Company Revenue (in millions) Profit (in millions)
25495 2005 496 Wm. Wrigley Jr. 3648.6 493
25496 2005 497 Peabody Energy 3631.6 175.4
25497 2005 498 Wendy’s International 3630.4 57.8
25498 2005 499 Kindred Healthcare 3616.6 70.6
25499 2005 500 Cincinnati Financial 3614.0 584

看上去不错。我们有需要的列,每一行对应一个公司一年的财务数据。

让我们重命名这些列,以便稍后引用它们。

df.columns = ['year', 'rank', 'company', 'revenue', 'profit']

接下来,我们需要探索我们的数据集,它是否完整? pandas 是按预期读的吗?缺少值吗?

len(df)

25500

好吧,看起来不错 —— 从 1955 年到 2005 年,每年都有 500 行。

让我们检查我们的数据集是否如我们预期的那样被导入。一个简单的检查就是查看数据类型(或 dtypes)是否被正确地解释。

df.dtypes

year         int64
rank         int64
company     object
revenue    float64
profit      object
dtype: object

看起来利润栏有点问题 —— 我们希望它像收入栏一样是 float64。这表明它可能包含一些非整数值,所以让我们看一看。

non_numberic_profits = df.profit.str.contains('[^0-9.-]')
df.loc[non_numberic_profits].head()

year rank company revenue profit
228 1955 229 Norton 135.0 N.A.
290 1955 291 Schlitz Brewing 100.0 N.A.
294 1955 295 Pacific Vegetable Oil 97.9 N.A.
296 1955 297 Liebmann Breweries 96.0 N.A.
352 1955 353 Minneapolis-Moline 77.4 N.A.

就像我们猜测的那样!其中一些值是字符串,用于表示丢失的数据。还有其他缺失的值么?

set(df.profit[non_numberic_profits])

{'N.A.'}

这很容易解释,但是我们应该怎么做呢?这取决于缺失了多少个值。

len(df.profit[non_numberic_profits])

369

它只是我们数据集的一小部分,虽然不是完全无关紧要,因为它仍然在 1.5% 左右。如果包含 N.A. 的行是简单地、均匀地按年分布的,那最简单的解决方案就是删除它们。所以让我们浏览一下分布。

bin_sizes, _, _ = plt.hist(df.year[non_numberic_profits], bins=range(1955, 2006))

粗略地看,我们可以看到,在一年中无效值最多的情况也小于 25,并且由于每年有 500 个数据点,删除这些值在最糟糕的年份中只占不到 4% 的数据。事实上,除了 90 年代的激增,大多数年份的缺失值还不到峰值的一半。为了我们的目的,假设这是可以接受的,然后移除这些行。

df = df.loc[~non_numberic_profits]
df.profit = df.profit.apply(pd.to_numeric)

我们看看有没有生效。

len(df)

25131

df.dtypes

year         int64
rank         int64
company     object
revenue    float64
profit     float64
dtype: object

不错!我们已经完成了数据集的设置。

如果你要将 notebook 做成一个报告,你可以不使用我们创建的研究的单元格,包括这里的演示使用 notebook 的工作流,合并相关单元格(请参阅下面的高级功能部分)并创建一个数据集设置单元格。这意味着如果我们把我们的数据放在别处,我们可以重新运行安装单元来恢复它。

使用 matplotlib 进行绘图

接下来,我们可以通过计算年平均利润来解决这个问题。我们不妨把收入也画出来,所以首先我们可以定义一些变量和一种方法来减少我们的代码。

group_by_year = df.loc[:, ['year', 'revenue', 'profit']].groupby('year')
avgs = group_by_year.mean()
x = avgs.index
y1 = avgs.profit

def plot(x, y, ax, title, y_label):
    ax.set_title(title)
    ax.set_ylabel(y_label)
    ax.plot(x, y)
    ax.margins(x=0, y=0)

现在让我们开始画图。

fig, ax = plt.subplots()
plot(x, y1, ax, 'Increase in mean Fortune 500 company profits from 1955 to 2005', 'Profit (millions)')

它看起来像一个指数,但它有一些大的凹陷。它们一定是对应于上世纪 90 年代初的经济衰退互联网泡沫。在数据中能看到这一点非常有趣。但为什么每次经济衰退后,利润都能恢复到更高的水平呢?

也许收入能告诉我们更多。

y2 = avgs.revenue
fig, ax = plt.subplots()
plot(x, y2, ax, 'Increase in mean Fortune 500 company revenues from 1955 to 2005', 'Revenue (millions)')

这为故事增添了另一面。收入几乎没有受到严重打击,财务部门的会计工作做得很好。

借助 Stack Overflow 上的帮助,我们可以用 +/- 它们的标准偏移来叠加这些图。

def plot_with_std(x, y, stds, ax, title, y_label):
    ax.fill_between(x, y - stds, y + stds, alpha=0.2)
    plot(x, y, ax, title, y_label)

fig, (ax1, ax2) = plt.subplots(ncols=2)
title = 'Increase in mean and std Fortune 500 company %s from 1955 to 2005'
stds1 = group_by_year.std().profit.as_matrix()
stds2 = group_by_year.std().revenue.as_matrix()
plot_with_std(x, y1.as_matrix(), stds1, ax1, title % 'profits', 'Profit (millions)')
plot_with_std(x, y2.as_matrix(), stds2, ax2, title % 'revenues', 'Revenue (millions)')
fig.set_size_inches(14, 4)
fig.tight_layout()

这是惊人的,标准偏差是巨大的。一些财富 500 强的公司赚了数十亿,而另一些公司却损失了数十亿美元,而且随着这些年来利润的增长,风险也在增加。也许有些公司比其他公司表现更好;前 10% 的利润是否或多或少会比最低的10%稳定一些?

接下来我们有很多问题可以看,很容易看到在 notebook 上的工作流程是如何与自己的思维过程相匹配的,所以现在是时候为这个例子画上句号了。这一流程帮助我们在无需切换应用程序的情况下轻松地研究我们的数据集,并且我们的工作可以立即共享和重现。如果我们希望为特定的目标人群创建一个更简洁的报告,我们可以通过合并单元和删除中间代码来快速重构我们的工作。

分享你的 notebook

当人们谈论分享他们的 notebook 时,他们通常会考虑两种模式。大多数情况下,个人共享其工作的最终结果,就像本文本身一样,这意味着共享非交互式的、预渲染的版本的 notebook;然而,也可以在 notebook 上借助诸如 Git 这样的辅助版本控制系统进行协作。

也就是说,有一些新兴的公司在 web 上提供了在云中运行交互式 Jupyter Notebook 的能力。

在你分享之前

当你导出或保存它时,共享的 notebook 将会以被导出或保存的那一刻的状态显示,包括所有代码单元的输出。因此,为了确保你的 notebook 是共享的,你可以在分享之前采取一些步骤:

  1. 点击 “Cell > All Output > Clear”
  2. 点击 “Kernel > Restart & Run All”
  3. 等待您的代码单元完成执行,并检查它们是否按预期执行。

这将确保你的 notebook 不包含中间输出,不包含陈旧的状态,并在共享时按顺序执行。

导出你的 notebook

Jupyter 内置支持导出 HTML 和 PDF 以及其他几种格式,你可以在 File > Download As 菜单下找到。如果你希望与一个小型的私有组共享你的 notebook,这个功能很可能是你所需要的。事实上,许多学术机构的研究人员都有一些公共或内部的网络空间,因为你可以将一个 notebook 导出到一个 HTML 文件中,Jupyter notebook 可以成为他们与同行分享成果的一种特别方便的方式。

但是,如果共享导出的文件并不能让你满意,那么还有一些更直接的非常流行的共享 .ipynb 文件到网上的方法。

GitHub

截止到 2018 年初,GitHub 上的公共 notebook 数量超过了 180 万,它无疑是最受欢迎的与世界分享 Jupyter 项目的独立平台。GitHub 已经集成了对 .ipynb 的文件渲染的支持,你可以直接将其存储在其网站的仓库和 gists 中。如果你还不知道,GitHub 是一个代码托管平台,用于为使用 Git 创建的存储库进行版本控制和协作。你需要创建一个帐户来使用他们的服务,同时 Github 标准帐户是免费的。

当你有了 GitHub 账户,在 GitHub 上共享一个 notebook 最简单的方法甚至都不需要 Git。自 2008 年以来, GitHub 为托管和共享代码片段提供了Gist 服务,每个代码段都有自己的存储库。使用 Gists 共享一个 notebook:

  1. 登录并且浏览 gist.github.com
  2. 用文件编辑器打开 .ipynb 文件, 全选并且拷贝里面的 JSON 。
  3. 将笔记的 JSON 粘贴到中 gist 中。
  4. 给你的 Gist 命名, 记得添加 .iypnb 后缀,否则不能正常工作。
  5. 点击 “Create secret gist”或者 “Create public gist.”

这看起来应该是这样的:

如果你创建了一个公共的 Gist,你现在就可以和任何人分享它的 URL,其他人将能够 fork 和 clone 你的工作。

创建自己的 Git 存储库并在 GitHub 上共享,这超出了本教程的范围,但是 GitHub 提供了大量的指南可供你参考。

对于那些使用 git 的人来说,一个额外的技巧是在 .gitignore 中为 Jupyter 创建的 .ipynb_checkpoints 目录添加例外,因为我们不需要将检查点文件提交给到仓库。

从 2015 年起,NBViewer 每个星期都会渲染成千上万的 notebook,它已然成了最受欢迎的 notebook 渲染器。如果你已经在某个地方把你的 Jupyter Notebook 放在网上,无论是 GitHub 还是其他地方,NBViewer 都可以读取你的 notebook,并提供一个可共享的 URL。作为项目 Jupyter 的一部分提供的免费服务,你可以在 nbview.jupyter.org 找到相关服务。

最初是在 GitHub 的 Jupyter Notebook 集成之前开发的,NBViewer 允许任何人输入 URL、Gist ID 或 GitHub username/repo/filename,并将其作为网页呈现。一个 Gist 的 ID 是其 URL 末尾唯一的数字;例如,在 https://gist.github.com/username/50896401c23e0bf417e89e1de 中最后一个反斜杠后的字符串。如果你输入了 GitHub username/repo/filename ,你将看到一个最小的文件浏览器,它允许你访问用户的仓库及其内容。

NBViewer 显示的 notebook 的 URL 是基于正在渲染的 notebook 的 URL 的并且不会改变,所以你可以和任何人分享它,只要原始文件保持在线 —— NBViewer 不会缓存文件很长时间。

结语

从基础知识入手,我们已经掌握了 Jupyter Notebook 的工作流程,深入研究了IPython 的更多高级功能,并最终学会如何与朋友、同事和世界分享我们的工作。我们从一个笔记上完成了这一切!

可以看到,notebook 是如何通过减少上下文切换和在项目中模拟自然的思维发展的方式来提高工作经验的。Jupyter Notebook。Jupyter Notebook 的功能也应该是显而易见的,我们已经介绍了大量的资源,让你开始在自己的项目中探索更高级的特性。

Default image
LIU
代码是躯体,思想是灵魂

Leave a Reply