IPython ノートブックをバージョン管理下に置くための良い戦略は何ですか?
ノートブックフォーマットはバージョン管理に非常に適しています。ノートブックと出力のバージョン管理をしたいのなら、これは非常にうまくいきます。特に映画やプロットの場合、大きなバイナリBLOBになる可能性があるセル出力(別名、 "build products")を除いて、入力をバージョン管理するだけの場合は厄介です。特に、私は良いワークフローを見つけようとしています。
すでに述べたように、出力を含めることを選択した場合(たとえば nbviewer を使用するときに望ましい)、すべて問題ありません。問題は、Iが出力をバージョン管理したくない場合です。ノートブックの出力を削除するためのツールやスクリプトがいくつかありますが、よく次のような問題が発生します。
Cell/All Output/Clear
メニューオプションと比較してフォーマットがわずかに変更されるため、差分に不要なノイズが発生するものがあります。これはいくつかの答えによって解決されます。以下で議論するいくつかの選択肢を検討しましたが、まだ良い包括的な解決策を見つけるには至っていません。完全な解決策はIPythonへのいくつかの変更を必要とするかもしれません、またはいくつかの単純な外部スクリプトに頼るかもしれません。私は現在 Mercurial を使用していますが、 git でも動作するソリューションが欲しいのですが、理想的なソリューションはバージョン管理にとらわれないでしょう。
この問題は何度も議論されてきましたが、ユーザーの観点から決定的または明確な解決策はありません。この質問に対する答えは決定的な戦略を提供するはずです。最近の(開発中の)バージョンの IPython または簡単にインストールできる拡張機能が必要な場合は問題ありません。
更新:私は Gregory Crosswhiteの提案 を使って保存するたびに.clean
バージョンを保存する my modified [ バージョンで遊んでいます。これは私の制約の大部分を満たしますが、未解決のままにします:
.clean
ファイルに入ってきて、それからどういうわけか私の作業バージョンに統合する必要があります。 (もちろん、いつでもノートブックを再実行することができますが、特に長い計算や並列計算などに結果が左右される場合は、これが面倒になることがあります)これを解決する方法についてはまだよくわかりません。 。おそらく ipycache のような拡張を含むワークフローはうまくいくかもしれませんが、それは少し複雑すぎるようです。Cell/All Output/Clear
メニューオプションを使うことができます。これが私のgitによる解決策です。通常どおり追加およびコミット(および差分)するだけです。これらの操作は作業ツリーを変更せず、同時にノートブックを(再)実行してもgit履歴は変更されません。
これはおそらく他のVCSに適合させることができますが、あなたの要件(少なくともVSCの不可知性)を満たさないことは知っています。それでも、それは私にとって完璧であり、それは特に素晴らしいものではなく、多くの人がおそらく既に使用していますが、グーグルでそれを実装する方法についての明確な指示は見つかりませんでした。だから、他の人に役立つかもしれません。
~/bin/ipynb_output_filter.py
と仮定します)chmod +x ~/bin/ipynb_output_filter.py
)次の内容のファイル~/.gitattributes
を作成します
*.ipynb filter=dropoutput_ipynb
次のコマンドを実行します。
git config --global core.attributesfile ~/.gitattributes
git config --global filter.dropoutput_ipynb.clean ~/bin/ipynb_output_filter.py
git config --global filter.dropoutput_ipynb.smudge cat
できた!
制限:
somebranch
にいてgit checkout otherbranch; git checkout somebranch
を実行している場合、通常は作業ツリーが変更されないと予想します。代わりに、2つのブランチ間でソースが異なるノートブックの出力とセル番号付けが失われます。git commit notebook_file.ipynb
をbase64ガベージから解放しますが、git diff notebook_file.ipynb
以上のものが必要になることに注意してください)。私の解決策は、個人的に生成されたものをバージョン管理したくないという事実を反映しています-出力を含むマージを行うと、出力またはあなたの生産性or両方。
編集:
私が提案したようにソリューションを採用する場合-つまり、グローバルに-いくつかのgitリポジトリの場合に問題が発生しますwantバージョン出力に。したがって、特定のgitリポジトリの出力フィルタリングをdisableしたい場合は、その中にファイル。git/info/attributesと
**。ipynb filter =
コンテンツとして。明らかに、同じ方法で反対のことを行うことが可能です。特定のリポジトリに対してフィルタリングonlyを有効にします。
コードは独自に維持されるようになりました git repo
上記の手順でImportErrorsが発生する場合は、スクリプトのパスの前に「ipython」を追加してみてください。
git config --global filter.dropoutput_ipynb.clean ipython ~/bin/ipynb_output_filter.py
編集:2016年5月(2017年2月に更新):私のスクリプトにいくつかの選択肢があります-完全を期すために、私が知っているもののリストを以下に示します: nbstripout ( othervariants )、 nbstrip 、 jq .
製品がJupyter Notebooksである共同プロジェクトがあり、過去6か月間、うまく機能しているアプローチを使用しました:.py
ファイルを自動的に保存し、.ipynb
ファイルと.py
ファイルの両方を追跡します。
そうすれば、誰かが最新のノートブックを表示/ダウンロードしたい場合、githubまたはnbviewerを介してそれを行うことができ、ノートブックのコードがどのように変更されたかを見たい場合は、.py
ファイルへの変更を見るだけです。
Jupyter
ノートブックサーバーの場合、これは行を追加することで実現できます。
import os
from subprocess import check_call
def post_save(model, os_path, contents_manager):
"""post-save hook for converting notebooks to .py scripts"""
if model['type'] != 'notebook':
return # only do this for notebooks
d, fname = os.path.split(os_path)
check_call(['jupyter', 'nbconvert', '--to', 'script', fname], cwd=d)
c.FileContentsManager.post_save_hook = post_save
jupyter_notebook_config.py
ファイルに追加し、ノートブックサーバーを再起動します。
jupyter_notebook_config.py
ファイルを見つけるディレクトリがわからない場合は、jupyter --config-dir
と入力できます。ファイルが見つからない場合は、jupyter notebook --generate-config
と入力して作成できます。
Ipython 3
ノートブックサーバーの場合、これは行を追加することで実現できます
import os
from subprocess import check_call
def post_save(model, os_path, contents_manager):
"""post-save hook for converting notebooks to .py scripts"""
if model['type'] != 'notebook':
return # only do this for notebooks
d, fname = os.path.split(os_path)
check_call(['ipython', 'nbconvert', '--to', 'script', fname], cwd=d)
c.FileContentsManager.post_save_hook = post_save
ipython_notebook_config.py
ファイルに追加し、ノートブックサーバーを再起動します。これらの行はgithubの問題の回答 @ minrk提供 からのものであり、@ drorは彼のSO回答にも含まれています。
Ipython 2
ノートブックサーバーの場合、これは次を使用してサーバーを起動することで実現できます。
ipython notebook --script
または行を追加することにより
c.FileNotebookManager.save_script = True
ipython_notebook_config.py
ファイルに追加し、ノートブックサーバーを再起動します。
ipython_notebook_config.py
ファイルを見つけるディレクトリがわからない場合は、ipython locate profile default
と入力できます。ファイルが見つからない場合は、ipython profile create
と入力して作成できます。
このアプローチを使用しているgithub上のプロジェクト :と ノートブックの最近の変更を調査するgithubの例 です。
これにとても満足しています。
両方のGitをサポートする MinRK Gist に基づいて、 nbstripout
を作成しました。そしてMercurial(mforbesに感謝します)。これは、コマンドラインでスタンドアロンで使用するか、またはnbstripout install
/nbstripout uninstall
を介して現在のリポジトリに簡単に(アン)インストールされるフィルタとして使用することを目的としています。
PyPI または単にそれから入手
pip install nbstripout
これは、IPython 3.0用のCyrille Rossantによる新しい解決策です。これは、jsonベースのipymdファイルではなく、マークダウンファイルを永続化するものです。
(2017-02)
戦略
nbstripout
、)nbstripout
、)nbconvert
:name.ipynb.py(nbconvert
)nbconvert
、ipymd
)ツール
nbstripout
:ノートブックから出力を取り除くpip install nbstripout; nbstripout install
ipynb_output_filter
:ノートブックから出力を取り除くipymd
:{Jupyter、Markdown、O'Reilly Atlas Markdown、OpenDocument、.py}の間で変換するnbdime
: "Jupyterノートブックの差分とマージのためのツール" (2015)nbdiff
:端末にやさしい方法でノートブックを比較するnbmerge
:自動衝突解決機能を備えたノートブックの3者間マージnbdiff-web
:ノートブックのリッチレンダリングされた差分を表示しますnbmerge-web
:ノートブック用のWebベースの3方向マージツールを提供しますnbshow
:端末にやさしい方法で単一のノートブックを表示するで指摘されているように、--script
は3.x
では非推奨です。このアプローチはpost-save-hookを適用することで使用できます。特に、ipython_notebook_config.py
に以下を追加します。
import os
from subprocess import check_call
def post_save(model, os_path, contents_manager):
"""post-save hook for converting notebooks to .py scripts"""
if model['type'] != 'notebook':
return # only do this for notebooks
d, fname = os.path.split(os_path)
check_call(['ipython', 'nbconvert', '--to', 'script', fname], cwd=d)
c.FileContentsManager.post_save_hook = post_save
コードは #8009 から取得されます。
JupyterとGitをうまく組み合わせるための生産的で簡単な方法がようやく見つかりました。まだ最初のステップに入っていますが、他のものよりずっと優れていると思います複雑な解決策。
Visual Studio Code は、Microsoftの優れたオープンソースのコードエディタです。それは今あなたが Jupyter Notebook をpythonコードとしてインポートすることを可能にする優れたPython拡張を持っています。
ノートブックをpythonファイルにインポートした後、すべてのコードとマークダウンは通常のpythonファイルにまとめられ、コメント内に特別なマーカーが付きます。あなたは下の画像で見ることができます:
あなたのpythonファイルは単にノートブックの入力セルの内容を持っています。出力は分割ウィンドウに生成されます。ノートブックには純粋なコードがありますが、実行しても変わりません。あなたのコードと混ざった出力はありません。あなたの差分を分析するための、奇妙なJsonの不可解なフォーマットはありません。
あなたはすべてのすべてのdiffを簡単に識別できる純粋なpythonコードです。
もう.ipynb
ファイルをバージョン管理する必要すらありません。 *.ipynb
に.gitignore
行を入れることができます。
他の人と公開したり共有したりするためのノートブックを作成する必要がありますか。問題ありません。対話型Pythonウィンドウで エクスポートボタン をクリックするだけです。
私は一日だけそれを使ってきました、しかしついに私はGitと共にJupyterをうまく使うことができます。
P.S .: VSCodeのコード補完はJupyterよりずっと良いです。
ノートブックの出力を数年間削除した後、私はより良い解決策を考え出しました。 Jupytext を使用しました。これは、Jupyter Notebookと私が設計したJupyter Labの両方の拡張機能です。
Jupytextは、Jupyterノートブックをさまざまなテキスト形式(スクリプト、マークダウン、Rマークダウン)に変換できます。そして逆に。また、ノートブックをこれらの形式のいずれかにpairペアリングし、ノートブックの2つの表現を自動的に同期するオプション(.ipynb
および.md/.py/.R
ファイル)。
Jupytextが上記の質問にどのように答えるかを説明します。
出力を含めるか除外するかを選択できます。
.md/.py/.R
ファイルには、入力セルのみが含まれます。このファイルは常に追跡する必要があります。出力を追跡する場合にのみ、.ipynb
ファイルをバージョン管理します。
望まない場合に誤って出力をコミットするのを防ぎます。
*.ipynb
を.gitignore
に追加します
ローカルバージョンで出力を保持できます。
出力は(ローカル).ipynb
ファイルに保存されます
バージョン管理システムを使用して入力に変更があるときを確認できます(つまり、入力をバージョン管理するだけで、ローカルファイルに出力がある場合、入力が変更されたかどうかを確認できます(コミットが必要です) )。ローカルファイルには出力があるため、バージョン管理ステータスコマンドを使用すると、常に差分が登録されます。)
.py/.R
または.md
ファイルの差分が探しているものです
更新されたクリーンなノートブックから作業中のノートブック(出力を含む)を更新できます。 (更新)
.py/.R
または.md
ファイルの最新リビジョンを取得し、Jupyterでノートブックを更新します(Ctrl + R)。テキストファイルから最新の入力セルを取得し、.ipynb
ファイルから一致する出力を取得します。カーネルは影響を受けません。これは、ローカル変数が保持されることを意味します-そのままの場所で作業を続けることができます。
Jupytextで気に入っているのは、ノートブック(.py/.R
または.md
ファイルの形式)をお気に入りのIDEで編集できることです。このアプローチにより、ノートブックのリファクタリングが簡単になります。完了したら、Jupyterでノートブックを更新するだけです。
試してみたい場合:Jupytextをpip install jupytext
でインストールし、JupyterノートブックまたはLabエディターを再起動します。バージョン管理するノートブックを開き、Jupyterノートブックで Jupytext Men を使用して、Markdownファイル(またはスクリプト)とペアリングします(または Jupytextコマンド Jupyter Lab)。ノートブックを保存すると、元の.ipynb
と、約束されたノートブックのテキスト表現の2つのファイルが得られます。これはバージョン管理に最適です。
興味があるかもしれない人のために:Jupytextは command line でも利用可能です。
私はとても実用的なアプローチを使います。いくつかのノートブック、それぞれの側面でうまく機能します。そしてそれは私が周りにノートを「転送」することさえ可能にします。 WindowsでもUnix/MacOSとして動作します。
アルはそれが単純だと思った、上記の問題を解決することです...
基本的に、donotは.ipnyb
-ファイルを追跡せず、対応する.py
-ファイルのみを追跡します。--script
オプションを指定してnotebook-serverを開始すると、そのファイルはノートブックの保存時に自動的に作成/保存されます。
これらの.py
-ファイルにはすべての入力が含まれています。非コードはセルの枠線と同様にコメントに保存されます。それらのファイルは、ノートブックを(再)作成するために、ノートブックサーバーに読み込み/インポート(そしてドラッグ)することができます。出力だけが消えています。再実行されるまで。
個人的には.py
ファイルをバージョン追跡するためにMercurialを使います。通常の(コマンドライン)コマンドを使用して追加し、チェックイン(ect)します。他のほとんどの(D)VCSはこれを可能にします。
今すぐ履歴を追跡するのは簡単です。 .py
は小さく、テキスト的であり、diffに簡単です。時々、私たちはクローン(ただ分岐します。そこで2番目のノートブックサーバーを起動します)、または古いバージョン(チェックアウトしてノートブックサーバーにインポート)などが必要です。
--script
オプション付きで)サーバーを起動し、それをバージョン追跡します。.py
-ファイルは保存されますが、notはチェックインされます。file@date+rev.py
)をチェックアウトすると便利です。それを追加するのは大変な作業です。そしてたぶん私はそうするでしょう。今まで、私はそれを手作業でやっています。残念ながら、私はMercurialについてあまり知りませんが、Gitコマンドをそれらの同等のMercurialに変換できる可能性があることを期待して、Gitと連携する可能性のある解決策を提供できます。
背景として、Gitではadd
コマンドはファイルに加えられた変更をステージング領域に格納します。これを実行すると、それ以降のファイルへの変更は、それをステージングするように指示しない限り、Gitによって無視されます。したがって、次のスクリプトは、指定された各ファイルについて、すべてのoutputs
とPrompt_number sections
を削除し、削除されたファイルをステージングしてから元のファイルを復元します。
注:これを実行するとImportError: No module named IPython.nbformat
のようなエラーメッセージが表示される場合は、ipython
ではなくpython
を使用してスクリプトを実行してください。
from IPython.nbformat import current
import io
from os import remove, rename
from shutil import copyfile
from subprocess import Popen
from sys import argv
for filename in argv[1:]:
# Backup the current file
backup_filename = filename + ".backup"
copyfile(filename,backup_filename)
try:
# Read in the notebook
with io.open(filename,'r',encoding='utf-8') as f:
notebook = current.reads(f.read(),format="ipynb")
# Strip out all of the output and Prompt_number sections
for worksheet in notebook["worksheets"]:
for cell in worksheet["cells"]:
cell.outputs = []
if "Prompt_number" in cell:
del cell["Prompt_number"]
# Write the stripped file
with io.open(filename, 'w', encoding='utf-8') as f:
current.write(notebook,f,format='ipynb')
# Run git add to stage the non-output changes
print("git add",filename)
Popen(["git","add",filename]).wait()
finally:
# Restore the original file; remove is needed in case
# we are running in windows.
remove(filename)
rename(backup_filename,filename)
変更をコミットしたいファイルに対してスクリプトが実行されたら、git commit
を実行します。
完璧な解決策のように見える "jupytext"に出くわすだけです。ノートブックから.pyファイルを生成してから、両方を同期させます。出力を失うことなく、.pyファイルを介してバージョン管理、差分の入力、マージ入力を行うことができます。ノートブックを開くと、入力セルには.py、出力には.ipynbが使用されます。そして、もしあなたがgitに出力を含めたいのなら、あなたはただipynbを追加することができます。
上記の非常に人気のある2016の回答は、2019年にこれを行うためのより良い方法と比較して矛盾したハックです。
いくつかの選択肢がありますが、質問に答えるのに最も良いのはJupytextです。
Jupytextの データ科学に向けた記事 をご覧ください。
バージョン管理で機能する方法は、.pyファイルと.ipynbファイルの両方をバージョン管理に置くことです。入力差分が必要な場合は.pyを、最新のレンダリング出力が必要な場合は.ipynbを見てください。
注目すべき言及:VSスタジオ、nbconvert、nbdime、水素
私はもう少しの作業で、VSスタジオおよび/または水素(または類似のもの)がこのワークフローに対する解決策の主役になるだろうと思います。
私はこの問題を解決するpythonパッケージを作りました
https://github.com/brookisme/gitnb
それはあなたのgitリポジトリ内のノートブックを追跡/更新/比較するためのgit風の構文をCLIに提供します。
ヘレスの例
# add a notebook to be tracked
gitnb add SomeNotebook.ipynb
# check the changes before commiting
gitnb diff SomeNotebook.ipynb
# commit your changes (to your git repo)
gitnb commit -am "I fixed a bug"
私が "gitnb commit"を使っている最後のステップは、あなたのgitリポジトリにコミットすることです。その本質的なラッパー
# get the latest changes from your python notebooks
gitnb update
# commit your changes ** this time with the native git commit **
git commit -am "I fixed a bug"
さらにいくつかの方法があり、各段階でより多くのまたはより少ないユーザ入力を必要とするように構成することができますが、それは一般的な考え方です。
Pietro Battistonによる優れたスクリプトをフォローアップするには、次のようにUnicodeの構文解析エラーが発生したら:
Traceback (most recent call last):
File "/Users/kwisatz/bin/ipynb_output_filter.py", line 33, in <module>
write(json_in, sys.stdout, NO_CONVERT)
File "/Users/kwisatz/anaconda/lib/python2.7/site-packages/IPython/nbformat/__init__.py", line 161, in write
fp.write(s)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2014' in position 11549: ordinal not in range(128)
スクリプトの冒頭に追加することができます。
reload(sys)
sys.setdefaultencoding('utf8')
調べた後、私はついにJupyterのドキュメントに という比較的単純なpre-saveフックを見つけました 。セル出力データを取り除きます。これをjupyter_notebook_config.py
ファイルに貼り付ける必要があります(手順については下記を参照)。
def scrub_output_pre_save(model, **kwargs):
"""scrub output before saving notebooks"""
# only run on notebooks
if model['type'] != 'notebook':
return
# only run on nbformat v4
if model['content']['nbformat'] != 4:
return
for cell in model['content']['cells']:
if cell['cell_type'] != 'code':
continue
cell['outputs'] = []
cell['execution_count'] = None
# Added by binaryfunt:
if 'collapsed' in cell['metadata']:
cell['metadata'].pop('collapsed', 0)
c.FileContentsManager.pre_save_hook = scrub_output_pre_save
どのディレクトリで
jupyter_notebook_config.py
ファイルを見つけるのかわからない場合は、[jupyter --config-dir
]を[Prompt/terminal]コマンドに入力します。ファイルが見つからない場合は、jupyter notebook --generate-config
と入力して作成できます。
私はAlbert&Richがしたことをしました - .ipynbファイルをバージョン管理しないでください(これらには画像が含まれる可能性があるため、面倒になります)。代わりに、常にipython notebook --script
を実行するか、c.FileNotebookManager.save_script = True
を設定ファイルに入れることで、ノートブックを保存するときに(バージョン対応可能な).py
ファイルが常に作成されるようにします。
ノートブックを再生成するには(リポジトリをチェックアウトしたりブランチを切り替えたりした後)、私はノートブックを保存するディレクトリにスクリプト py_file_to_notebooks.py を置きます。
さて、リポジトリをチェックアウトした後、python py_file_to_notebooks.py
を実行してipynbファイルを生成するだけです。ブランチを切り替えた後、既存のipynbファイルを上書きするためにpython py_file_to_notebooks.py -ov
を実行しなければならないかもしれません。
念のために、*.ipynb
ファイルに.gitignore
を追加してください。
編集:私はもうこれをしません。なぜなら(A)あなたがブランチをチェックアウトする度にあなたはあなたのノートブックをpyファイルから再生成しなければならないからです。代わりにgitフィルタを使ってノートブックから出力を取り除きます。これを行う方法についての議論はここ です 。
さて、議論 here によると、現在の最良の解決策のように見えますが、コミット時にipynbファイルから出力を自動的に取り除くgitフィルターを作成することです。
これを機能させるために私がしたことは次のとおりです(その議論からコピー)。
最新のIPythonをインポートできない場合は、cfriedlineのnbstripoutファイルをわずかに変更して情報エラーを表示しました: https://github.com/petered/plato/blob/fb2f4e252f50c79768920d0e47b870a8d799e92b/notebooks/config/strip_notebook_output そしてそれを私のレポに追加しました、./relative/path/to/strip_notebook_output
で言ってみましょう
また、以下を含む.gitattributesファイルをリポジトリのルートに追加しました。
*.ipynb filter=stripoutput
そしてsetup_git_filters.sh
を作成しました
git config filter.stripoutput.clean "$(git rev-parse --show-toplevel)/relative/path/to/strip_notebook_output"
git config filter.stripoutput.smudge cat
git config filter.stripoutput.required true
source setup_git_filters.sh
を実行しました。素晴らしい$(git rev-parse ...)のことは、(Unix)マシン上でリポジトリのローカルパスを見つけることです。
このjupyter拡張機能により、ユーザーはjupyterノートブックを直接githubにプッシュできます。
こちらをご覧ください
以下の記事でノートブックの出力を保存する場所について考えてみてください。ノートを生成するには長い時間がかかるかもしれないという議論があり、GitHubがノートブックをレンダリングできるようになったので便利です。ノートブックやgitを使用していないチームメンバーと共有するためのdiffや.htmlに使用される.pyファイルのエクスポート用に自動保存フックが追加されています。
https://towardsdatascience.com/version-control-for-jupyter-notebook-3e6cef13392d