实时 Notebook

您可以在 实时会话 中运行此 notebook,或在 Github 上查看它。Binder

分析网络托管的 JSON 数据

本 notebook 使用 Dask BagDask DataFrame 的组合读取并处理网络托管的 JSON 编码数据。

这些数据来自 mybinder.org,这是一个在网络上实时运行 Jupyter notebook 的网络服务(您现在可能正在那里运行此 notebook)。My Binder 发布每次有人启动像这样的实时 notebook 的记录,并将该记录存储在一个公开可访问的 JSON 文件中,每天一个文件。

数据集介绍

这些数据以 JSON 编码文本文件的形式存储在公共网络上。以下是一些示例行。

[ ]:
import dask.bag as db
db.read_text('https://archive.analytics.mybinder.org/events-2018-11-03.jsonl').take(3)

我们看到它包含该网站上每次有人启动实时 notebook 的一条记录。它包括 notebook 启动的时间以及提供该 notebook 的仓库。

在此 notebook 中,我们将查看许多此类文件,将它们从 JSON 解析为 Python 字典,然后从中转换为 Pandas 数据帧。然后,我们将对这些数据进行一些简单的分析。

启动 Dask Client 以查看仪表盘

启动 Dask Client 是可选的。它将启动仪表盘,这对于深入了解计算很有用。

[ ]:
from dask.distributed import Client, progress
client = Client(threads_per_worker=1,
                n_workers=4,
                memory_limit='2GB')
client

获取网络上的文件列表

mybinder.org 团队维护着一个索引文件,该文件指向所有其他可用的 JSON 数据文件。让我们将其转换为 URL 列表,以便在下一节中读取。

[ ]:
import dask.bag as db
import json
[ ]:
db.read_text('https://archive.analytics.mybinder.org/index.jsonl').map(json.loads).compute()
[ ]:
filenames = (db.read_text('https://archive.analytics.mybinder.org/index.jsonl')
               .map(json.loads)
               .pluck('name')
               .compute())

filenames = ['https://archive.analytics.mybinder.org/' + fn for fn in filenames]
filenames[:5]

创建包含所有事件的 Bag

我们现在围绕该 URL 列表创建一个 Dask Bag,然后对每一行调用 json.loads 函数,将这些 JSON 编码的文本行转换为可以更容易操作的 Python 字典。

[ ]:
events = db.read_text(filenames).map(json.loads)
events.take(2)

转换为 Dask DataFrame

最后,我们可以将我们的 Python 字典 bag 转换为 Dask DataFrame,然后进行更多类似 Pandas 的计算。

现在,我们将使用 Pandas 语法执行与上面相同的计算。

[ ]:
df = events.to_dataframe()
df.head()
[ ]:
df.spec.value_counts().nlargest(20).to_frame().compute()

持久化到内存

这个数据集非常适合内存。为了避免每次操作都下载数据,我们可以将数据保留在本地内存中。

[ ]:
df = df.persist()

老实说,到目前为止,直接切换到 Pandas 更有意义,但这毕竟是 Dask 的示例,所以我们将继续使用 Dask DataFrame。

调查 Github 以外的提供商

大多数 Binder 都被指定为 GitHub 上的 git 仓库,但并非全部。让我们调查其他提供商。

[ ]:
import urllib
[ ]:
df.provider.value_counts().compute()
[ ]:
(df[df.provider == 'GitLab']
 .spec
 .map(urllib.parse.unquote, meta=('spec', object))
 .value_counts()
 .to_frame()
 .compute())
[ ]:
(df[df.provider == 'Git']
 .spec
 .apply(urllib.parse.unquote, meta=('spec', object))
 .value_counts()
 .to_frame()
 .compute())