Jupyter ノートブックをテキストに変換 — 無料・非公開

.ipynb ノートブックをブラウザーでプレーンテキストに変換します。JSON の外殻、埋め込み画像、セルのメタデータを取り除き、コードと文章だけを残します。

Jupyter Notebook をテキストに変換する:足場を外して中身だけ取り出す

渡す先が書式について何の主張も持たないとき、正しい変換先はプレーンテキストです。grep のパイプライン、diff、検索インデックス、剽窃チェック、添付を嫌う同僚へのテキストメール——どれもバッククォートやシャープ記号で良くなることはなく、いくつかはむしろ悪くなります。レンダラーには意味があり、読み手には何の意味もない記号だからです。

このコンバーターは .ipynb を受け取り、文章とコードを記法を足さずに返します。セルとセルのあいだは空行で区切られます。コードはフェンスなしでコードとして現れます。印字された結果は、それを生んだセルの下に素っ気ない Output: というラベルを付けて置かれます。JSON がその内容を包んでいたものはすべて捨てられます。作業はこのブラウザタブの中で行われます。

トークンの話

ノートブックを平坦化する最も一般的な理由は、下流のどこかがトークン課金で、生の .ipynb は「ほとんど何も言っていないのに高くつく」表現だからです。この比率は具体的に見ておく価値があります。

セルが三十個、うち半分が図を描くノートブックは、ディスク上で二〜三メガバイトになるのが普通です。その中の文章とコードは八キロバイト程度かもしれません。残りはすべて base64 の画像データ、プレーンテキストとしても存在する結果の HTML の複製、そしてセルごとの帳簿です。生のファイルをモデルに渡すと、本来の百倍のコストがかかるだけでは済みません。たいていはそのまま失敗します。情報を運ばない文字でコンテキストウィンドウが埋まってしまうからです。

さらに悪いことに、base64 はトークナイザーとの相性が最悪です。普通の英文は平均して四文字で一トークン程度です。ランダムな base64 には語彙が圧縮に使える繰り返しの部分文字列がないので、二文字で一トークンに近づきます。ファイルの中でいちばん役に立たない部分が、同時に文字あたりのトークン数がいちばん悪い部分でもあるわけです。上のカウンターは変換結果のトークン数を表示するので、実際に何を送ろうとしているのかが見えます。

平坦化しても残るもの

構造を取り除くことは意味を取り除くことではなく、この種のツールの成否はその境目にあります。残すものは次のとおりです。

  • markdown セルの内容は書かれたまま。#** は残します。markdown セルにおいて、それは著者が強調と階層を示す唯一の手段だからです。剥がしてしまえば、もともと文章だったものを区別のない文字の塊に潰すことになります。
  • コードは打たれたまま。インデントも維持し、コメントも残します。Python の意味は行頭の空白に依存するので、これは美意識の問題ではありません。
  • テキストの結果。印字された出力、返り値、データフレームのプレビューのプレーン形式。
  • エラー名、メッセージ、トレースバック。端末のカラーコードは取り除いたうえで残します。
  • raw セル。中身はたいてい、著者が手を入れられたくなかった LaTeX や reStructuredText です。

落とすものは、画像と動画のペイロード、PDF の添付、テキストとしても存在する結果の HTML の双子、実行回数、セル識別子、空のメタデータオブジェクト、そして中身のないセルです。空白しかなく出力もないセルは、誰も読む必要のないセルです。

図のプレースホルダーをどうするか

プロットを取り除いたあと、その跡を残すか残さないか。ここには本物のトレードオフがあります。何も残さなければ本文はきれいに読めますが、「上の図が示すように」といった一文が何も指さなくなります。プレースホルダーを残せば、ほとんど情報のない行を一本増やすことになります。

既定ではメディアの種類を書いた短い一行を残し、上のスイッチで消せます。関連して知っておくとよい細部があります。matplotlib は画像と並んでテキスト表現も出力し、その中身はいつも <Figure size 640x480 with 1 Axes> のようなものです。素直に残すと、その行とプレースホルダーが続けて並び、同じことを二度言うことになります。そこで図が落とされたときは、このテキストだけを抑制します。

中央から詰める

出力が長いのは、情報が多いからのこともあれば、ループが中で印字しているだけのこともあります。ツールにその区別はつかないので、各出力に上限を設け、中央から切り、先頭と末尾を残したうえで何文字が欠けたかを示します。

中央から詰めるほうが他の選択より良いのには、はっきりした理由があります。長い出力でいちばん情報量が多いのは、ほぼ必ず先頭——何が生まれたかの形が見える——と末尾——それがどこに着地したかが見える——の二か所です。末尾を切ったデータフレームは最初の数行を見せて集計行を隠し、先頭を切ったものは列名を隠します。中央を切れば、話の両端が残ります。

平らになったノートブックで楽になること

JSON が消えると、いくつかのことが簡単になります。二つのバージョンのノートブックをプレーンテキストで比較すれば、実行回数がいくつ増えたかではなく分析そのものの変化が見えます。nbdime が存在する理由は、そもそも普通の git diff.ipynb にかけても読めないからです。図を描いた関数をノートブックのフォルダーから探すのは、ただの grep になります。レポート用に文字数を数える、ノートブックを音声合成に渡す、手法の説明を Markdown を描画しない文書に貼る——どれも追加の掃除なしに通ります。

プライバシーが、ここでは構造の問題である理由

ノートブックは作業中の文書であり、作業中の文書には誰も残すつもりのなかったものが溜まります。API のデバッグ中に貼ったトークン、接続文字列、マージの確認のために印字した顧客データ二十行。それを変換サービスに渡すことは、中に入っているものを丸ごと渡すことです。

ここでのパーサーはこのタブで動く JavaScript です。ファイルはブラウザが読み、メモリ上で変換され、表示されます。アップロードがないので、信用すべき保持ポリシーもなく、依頼すべき削除もありません。フェンス付きのコードブロックと Markdown の見出しが欲しい場合は、ノートブックを Markdown に変換するツールが同じ保証のもとでそれを行います。