ここ最近は作業の多くをJupyterでやっています。
なんだかここ最近扱うものの多様さもあいまって、「コマンドの使い方を忘れる」とか「そもそも何のコマンドを使っていたか忘れる」みたいなことが多かったわけですが、普段からJupyter(IPython Notebook)上で作業していれば、実行した内容とそれに対応する出力の記録が残ってくれます。
こうしておけば、あとから見返して、必要であればそのNotebookを再利用して同じような作業を実施する、みたいなことができるわけです。
そんな中で似たようなNotebookが複数できしまい、それらのNotebookのdiffをとりたくなったので試した方法のメモ。
Notebookのファイル(.ipynb)とdiff
Notebookのファイル(.ipynb)はJSONファイルなのでdiff取っちゃえばいいじゃん、というのはあるのですが、Notebookのファイルには実行カウントや出力結果の情報もあわせて記録されているので、単純にdiffを取るのでは、出力などの実行時に関する情報も差分として現れてしまい、手順や説明だけの差分が見えにくくなってしまいます。
Using IPython notebooks under version control みたく、Gitでの操作時に出力結果を削っちゃうようなフィルタを施すというのもシンプルでよいなあ、とは思うのですが、出力結果も大事で、それはそれで残しておきたい・・・といった状況。
出力を無視したdiffの取り方
diffコマンドで差分を取る際に簡単に出力結果を削ることができるスクリプトを用意してみました。
まず、以下のスクリプトをダウンロードし、実行可能権限を付与しておいてください。
で、たとえば 1.ipynb
と 2.ipynb
の内容を、出力結果を無視して比較したい場合はbash上で以下のように実行すればOK。
$ diff <(./nbstripout 1.ipynb) <(./nbstripout 2.ipynb)
実行例
あるNotebook test-1.ipynb
から派生して別の環境向けのNotebook test-2.ipynb
を作った、みたいな状況を例に・・・
Notebookで実行操作をおこなうと、実行カウントが増えたり、たとえばcurlコマンドの実行など、ダウンロード速度などの実行時の状況により出力結果が変化するセルを含んでいれば実行結果が毎回変化したりします。
そのため、Notebookファイルをそのままdiffを取ってしまうと、outputやexecution_countのような実行に関する情報が差分として目立ってしまい、肝心の説明やコードに関する変更点がぼやけてしまうことがよくあります。
$ diff test-1.ipynb test-2.ipynb
9c9,13
< "出力セルだけ無視してdiffとりたい。"
---
> "出力セルだけ無視してdiffとりたい。\n",
> "\n",
> "##追加説明\n",
> "\n",
> "この場合はどういう背景で実行したんだっけみたいな説明。"
14c18
< "execution_count": 2,
---
> "execution_count": 3,
25c29
< "100 1535 100 1535 0 0 3953 0 --:--:-- --:--:-- --:--:-- 3956\n"
---
> "100 1535 100 1535 0 0 7802 0 --:--:-- --:--:-- --:--:-- 7791\n"
nbstripout
を通してdiffをとると以下のような感じで、execution_countやoutputの情報が除外されて、説明の部分だけが見えます。
$ diff <(./nbstripout test-1.ipynb) <(./nbstripout test-2.ipynb)
9c9,13
< "出力セルだけ無視してdiffとりたい。"
---
> "出力セルだけ無視してdiffとりたい。\n",
> "\n",
> "##追加説明\n",
> "\n",
> "この場合はどういう背景で実行したんだっけみたいな説明。"
この例ではexecution_countやoutputは大した行数ではありませんが、プロットを含んでいたり、多くの処理を実行するようなコマンドの出力結果が含まれていたりすると、非常に大きなものになってつらい気持ちになります。
参考
ベースとしたスクリプトは以下、
このスクリプト nbstripout
は引数に指定された.ipynbファイルを読み込み、execution_countやoutputを削ったのち、その.ipynbファイルを上書きする形になっています。
今回はdiffを取るだけで元のファイルは取っておきたいので、このGistをForkさせてもらって、outputなど削った.ipynbの内容を標準出力に出力するように nbstripout
を変更し、あとは、
を参考に、その標準出力の内容を比較すればいいだろう・・・という感じ。
後で気づく
http://nbdiff.org/ みたいなのもあるんですなあ・・・今度試してみたいなあ。