こんにちは!LegalscapeのLabsチームでAIエンジニアを務めている白水(@sorami)です。
Legalscapeは、AI技術の活用により「法情報の調査」を革新するサービスを開発するテックカンパニーです。その中でLabsチームは、AI・データサイエンスを担当し、情報検索や文章生成の改良、新たな技術のR&Dなど、AIとデータに関するさまざまな取り組みを進めています。
日々の業務の中で、コード・結果・ドキュメントをまとめられるインタラクティブ環境 Jupyter Notebook は、探索的なデータ分析や実験に欠かせないツールです。
しかし、これも完璧ではありません。特に再現性、つまり「同じノートブックを別の環境や別のタイミングで実行しても、同じ結果が得られるか」という問題は深刻で、業務にも直結します。データサイエンスに関わる方なら誰でも、チームメンバーから共有されたノートブックが違う挙動をしたり、自分が書いたノートブックでさえも動かなかったり結果が変わったりといった経験があるのではないでしょうか。
そこで本記事では、大規模調査の論文をはじめとする先行研究をもとに、この問題の実態や原因、対策を解説します(参照した文献の一覧は記事末尾の「参考文献」にまとめています)。
TL;DR
- ノートブックの普及と、再現性の実態
- GitHubで公開されている116万件のJupyter Notebookのうち、実行順序が明確な約86万件に対して再現を試みた結果、エラーなく実行できたのはその24%、元と同じ結果を再現できたのはわずか4%(Pimentel+ 2019)
- 査読済み論文でも結果一致は6%(Samuel & Mietchen 2024)
- 再現性を阻む要因
- Jupyterの仕様(実行順序のばらつきと隠れ状態、
.ipynbファイル形式の問題) - それが誘発する習慣(依存関係の未宣言、ドキュメント不足)
- Jupyterの仕様(実行順序のばらつきと隠れ状態、
- 習慣とツールによる対策
- Restart & Run All
- パッケージ管理ツールによる依存管理
- ノートブックの分割、インポートの集約、相対パスの利用といった基本的な作法
- nbstripout・jupytext・Papermill・nbQAなどのツール活用
- データサイエンスとソフトウェアエンジニアリングの間で
- 再現性の価値は理解されていても、それをコードで実現する手段(依存管理、テスト、バージョン管理等)はエンジニアリング側の専門知識
- 書き捨てのはずだったコードが、そのまま本番や論文に残りがち
- ノートブックの再発明へ
- 隠れ状態を設計レベルで排除するmarimoが次世代の選択肢として登場
ノートブックの普及と、再現性の実態
GitHub上のJupyter Notebookの数は、2017年の約123万件(Rule+ 2018)から2020年には約972万件(JetBrains 2020)へと約8倍に急増しました。その勢いは衰えておらず、Jupyter Notebookを含むリポジトリ数は2024年から2025年にかけて前年比+75%(約140万→242万)の伸びを見せています(GitHub Octoverse 2025)。AI・データサイエンス分野の広がりを反映した動きと言えるでしょう。
しかし、これほど普及しているのに、その再現性には深刻な問題があります。大規模データを用いた先行研究を見てみましょう。
Pimentel+ (2019): GitHub上の116万件から検証、結果一致はわずか4%
Pimentelらによる "A Large-scale Study about Quality and Reproducibility of Jupyter Notebooks"(MSR 2019)は、GitHubから収集した約116万件のJupyter Notebookを対象にした品質と再現性の大規模調査です。実行順序が明確な約86万件のノートブックに対して再現を試みた結果、エラーなく実行できたのは 24.11%、元と同じ結果を再現できたのはわずか 4.03%でした。
失敗の原因で最も多いのは ImportError(29%)で、依存ライブラリが宣言されておらずインストールできないケースです。次いで NameError(14.53%)は隠れ状態や非線形実行に起因し、FileNotFoundError(12.59%)は絶対パスの使用やデータの未同梱が原因です。
品質面でも、36% のノートブックが上から下への順番通りに実行されておらず、31% にはMarkdownセルが一つもありません。テストを書いているのは 1.54%、依存関係を requirements.txt 等で宣言しているリポジトリは 13.72% にとどまります。
Samuel & Mietchen (2024): 査読済み論文でさえ、ほとんど再現できない
上の結果は「カジュアルなノートブックだから仕方ない」と思うかもしれません。では、査読済みの学術論文に付随するノートブックではどうでしょうか。Samuel & Mietchen による "Computational Reproducibility of Jupyter Notebooks from Biomedical Publications"(GigaScience, 2024)は、PubMed Central掲載の生物医学論文に関連するノートブック約2.7万件を対象に、自動パイプラインで再現性を検証しました。
- 対象論文 3,467 件 → Jupyter含むリポジトリ 2,660 → ノートブック 27,271 件
- うちPython 22,578 件 → 依存関係インストール成功 10,388 件
- エラーなし実行 1,203 件(7.61%) → 結果一致 879 件(5.56%)
査読を通った論文でさえ、結果一致率は5.56%。ImportError の割合はPimentelの29%を上回る 42% で、依存関係の問題はむしろ悪化しています。一方で、依存関係を setup.py や requirements.txt で宣言しているノートブックは結果一致率が明確に高く、きちんと管理すれば再現性は上がるという実証データでもあります。
科学研究における「再現性の危機」が近年注目を集めていますが、計算的な研究が増える中で、ノートブックの再現性もそれと地続きの話題と言えるでしょう。
再現性を阻む要因
再現率がここまで低いのには、構造的な理由があります。問題はJupyter Notebookの仕様と、その仕様がもたらす習慣の二つの側面から整理できます。加えて、その背景にはデータサイエンスとソフトウェアエンジニアリングという二つの専門領域の違いがあると考えていますが、これについては後述します。
Jupyter Notebookの仕様からくる問題
ユーザーがどれだけ注意しても回避できない、ツール自体の仕様からくる問題です。
実行順序のばらつきと隠れ状態
Jupyter Notebookでは、上のセルに戻って変数を書き換えたり、途中のセルだけ再実行したりすることがよくあります。手軽ですが、この自由さが厄介な問題を引き起こします。
上から下への順番通りに実行されていないノートブックの割合は、Rule+ (2018) で 43.9%、Pimentel+ (2019) で 36%、JetBrains (2020) でも 36%。調査対象や時期が異なっても、一貫して3〜4割が非線形に実行されています。
こうしたばらつきが生むのが隠れ状態(hidden state)です。
- 順序外実行による矛盾: 上のセルで変数を書き換えたが、下流を再実行しない。メモリと保存されたコードの結果が食い違う
- 削除されたセルの幽霊: セルを削除しても、変数はカーネルのメモリに残る。別の環境で開けば
NameError(再現失敗の14.53%)につながる(Pimentel+ 2019)
セルを任意の順序で実行できるうえに、変更の影響が他のセルへ即時に反映されない。そのため、変数の状態が、コードと実行履歴の両方に依存します。コードを見ただけでは実際の値がわからないため、「その場では動いているように見えて、実は再現できないノートブック」が生まれてしまいます。
.ipynb ファイル形式の問題
.ipynb の正体はJSONで、コード・出力・メタデータがすべて混在しています。出力を含むJSONはファイルサイズが膨大になり、git diff ではコード変更が差分に埋もれる。バージョン管理やコードレビューが機能せず、コラボレーションによる品質担保の機会が失われています。
仕様がもたらす習慣の問題
原理的には改善できるものの、Jupyter Notebookの「やらなくても動く」仕様が悪い習慣をもたらしてしまう問題です。
依存関係の未宣言
再現失敗で最も多いエラーは、シンプルに「そもそもライブラリをインストールできない」というものです。
ImportError の割合は Pimentel+ (2019) で 29%、Samuel & Mietchen (2024) では 42%。一方、requirements.txt 等で依存関係を宣言しているリポジトリはわずか 13.72%(Pimentel+ 2019)。宣言があってもバージョン未固定が多く、インストール失敗率は 61〜68% に達します(Samuel & Mietchen 2024)。
Jupyterでは !pip install pandas でその場しのぎができ、.ipynb にはパッケージ環境を記録する仕組みもありません。依存管理のやり方と重要性を知らなければ、そもそもやらないのは自然なことでしょう。
ドキュメンテーションの不足
Markdownセルが一つもないノートブックは 27.6%(Rule+ 2018)〜31%(Pimentel+ 2019)。あっても冒頭に集中し、後半ほど説明が減ります。
手順を説明しているノートブックは88%と多いのに、推論の説明は34%、結論があるのはわずか3%(Rule+ 2018)。コードは自動的に残りますが、「なぜそうしたか」「結果が何を意味するか」は意識しなければ消えます。そして、探索的にコードを書きながら、同時に説明を整えるのは本質的に難しいものでしょう。
パスの問題
FileNotFoundError も再現失敗の 12.59% を占めます(Pimentel+ 2019)。絶対パスの使用やデータ未同梱が原因で、見落とされやすい割に影響が大きい問題です。
習慣とツールによる対策
前セクションで見た問題は、習慣の改善とツールの活用で大きく緩和できます。
隠れ状態への対策
手動で「Restart & Run All」
コミット前に、カーネルを再起動し、上から下まで通して実行する。最もシンプルで効果的な習慣です。これにより、途中の NameError を検出し、順次実行した際の一貫性ある出力を確認できます。
ノートブックでは、Kernelメニューやコマンドパレットから「Restart Kernel and Run All Cells...」を選択して実行できます。
ただし、これは人間の規律に頼ったアプローチであり、忘れたらそれまでです。また、重い処理があると毎回の再実行に時間がかかり、ますます省略されがちになります。
CLIで「Restart & Run All」
jupyter nbconvert --execute は、Restart & Run All をコマンドラインから実行するもので、エラーがあればそこで止まります。
jupyter nbconvert --to notebook --execute my_notebook.ipynb
コマンドなので、CI/CDパイプラインやシェルスクリプトに組み込んで自動化できます。
インポートの集約
インポートがセルの途中に散らばっていると、実行順序が変わったときに ImportError の原因になります。冒頭にまとめれば、必要なライブラリが一目瞭然です。PEP 8 でも推奨されている基本的な作法ですが、ノートブックだとつい崩れがちです。
ノートブックの分割
処理の段階ごとにノートブックを分けることで、管理のしやすさや可読性が向上します。
01-data-preparation.ipynb02-feature-engineering.ipynb03-model-training.ipynb
ノートブックが短くなれば、Restart & Run All も気軽にできます。ステップ間は中間ファイルでつなぐと良いでしょう。
依存関係への対策
パッケージ管理ツールによる依存関係の管理
依存関係の未宣言に対する最も効果的な対策です。uv を使えば、依存関係の宣言からクリーンな環境でのテストまで一気通貫で対応できます。uv lock でロックファイルを生成し、uv sync で依存関係を厳密に再現。仮想環境の作成も自動です。
前述の nbconvert --execute と組み合わせれば、クリーンな環境での再実行まで一度に確認できます。
uv sync uv run jupyter nbconvert --to notebook --execute my_notebook.ipynb
これが通れば、他の人の環境でも動く可能性はぐっと高まります。
相対パスの利用
/Users/yourname/data/... のような絶対パスは FileNotFoundError の元凶です。相対パスを使い、リポジトリに含められないデータはダウンロード方法を明記しましょう。
関連ツールの利用
バージョン管理の改善
ノートブックもバージョン管理すべきですが、コード・出力・メタデータがすべて混在する .ipynb のJSON形式がそれを困難にしています。以下のツールで、この問題にある程度対処できます。
nbstripout は、コミット時にノートブックの出力を自動除去するGitフィルターです。diffから出力やメタデータが消え、コードの変更だけが残ります。jupytext は、.ipynb と .py や .md を相互変換するツールで、ノートブックをプレーンテキストとして管理でき、diffもコードレビューも自然にできます。
パラメータ化と実行の記録
Papermill は、ノートブックに外部からパラメータを注入して実行するツールです。実行結果が別ファイルに保存されるので、「いつ・どんな条件で実行したか」の記録が自然に残ります。
リンター・フォーマッターの適用
Pythonには、コードの問題を検出するリンターやスタイルを自動整形するフォーマッター(ruff、black など)がありますが、これらは通常 .py ファイルを対象としています。nbQA を使えば、これらのツールをノートブックに対してもそのまま実行でき、.py ファイルと同じコード品質基準を適用できます。
データサイエンスとソフトウェアエンジニアリングの間で
ここまではJupyter Notebook固有の問題と対策を見てきました。こうした課題の背景には、より根本的な要因があると私は考えます。
データサイエンスとソフトウェアエンジニアリングは、異なる訓練体系と文化を持つ専門領域です。再現性の価値は、科学的手法に慣れたデータサイエンティストも理解しているでしょう。しかし、それをコードで実現する手段(依存管理、テスト、バージョン管理、コードレビューなど)はソフトウェアエンジニアリング側の専門知識であり、コードの品質や堅牢さに対する感度も両者では大きく異なります。
また、探索フェーズのコードを書き捨てること自体は合理的です。すべてにプロダクション品質を求めれば、探索そのものが阻害されます。しかし、書き捨てのはずだったコードは往々にして書き捨てられません。そのまま共有され、PoCがプロダクションの基盤になり、論文の記録になることは実際よくあります。こうした流れの中で、再現性の問題が顕在化します。
この分野では、『先輩データサイエンティストからの指南書』(2025)がまさにその観点から書かれた一冊です。環境構築、コードやデータの品質管理、実験管理、プロトタイピングまで、データサイエンティスト向けにエンジニアリングの知識を体系的に整理しています。以前、著者より献本いただいた際に書いた書評がありますので、興味のある方は併せてご覧ください。
ノートブックの再発明へ
先に見た対策はどれも有効ですが、すべてユーザーの規律や外部ツールで設計上の問題を補うアプローチです。そもそもJupyterは、セルを好きな順番で実行でき、カーネルがグローバルな状態を持ち続ける設計です。では、使い方ではなく設計そのものを再発明できないか。そういう発想のツールが登場しています。
リアクティブ実行とは、セルの値が変わったら依存するセルを自動的に再実行する仕組みです。スプレッドシートのセルが更新されると関連するセルが自動で再計算されるのと同じ発想で、実行順序をユーザーではなくシステムが管理します。JavaScriptの Observable やJuliaの Pluto.jl が先駆者であり、Pythonでは marimo がこのアプローチを採用しています。
marimoはノートブックを有向非巡回グラフ(DAG)として扱います。各セルが定義する変数と参照する変数を静的解析で検出し、セル間の依存関係をグラフとして構築します。あるセルが実行されると下流のセルが自動的に再実行され、セルが削除されればその変数も消えます。
この設計により、本記事で見てきた問題の多くが構造的に解消されます。
- 隠れ状態 → 実行順序をシステムが管理するので、順序外実行や削除されたセルの幽霊が原理的に発生しない
.ipynbの問題 → ファイル形式が純粋な.pyファイルでGitフレンドリー、コードレビューもしやすい。そのままPythonインポート可能、CLIからスクリプト実行可能、テキストエディタでも編集可能、AIにもやさしい- 依存関係の未宣言 → PEP 723のインラインメタデータを活用し、依存関係をファイル自体に埋め込むサンドボックスモードを提供している
私も、最近はJupyter Notebookではなくmarimoをメインに使い始めており、体験がとても良くかなり満足しています。これについてはまた機会があれば述べたいと思います。興味がある方は、ぜひチェックしてみてください 🥳
おわりに
本記事では、Jupyter Notebookの再現性について、先行研究を参考に、問題の実態・原因・対策を整理しました。Jupyterの設計に起因する問題や、それが誘発する習慣の問題がありますが、良い習慣の定着やツールの活用で状況は大きく改善できます。また、ソフトウェアエンジニアリングの知識を身につけ、そのベストプラクティスを取り入れていくことも重要でしょう。
インタラクティブな環境は、コンピューターというメディアの力を最大限に引き出すものです。コード・実行結果・説明を一つに統合するノートブックは、まさにその体現であり、探索的なデータ分析やプログラミング学習にとってかけがえのないツールです。本記事で取り上げた課題を解消していけば、ノートブックはもっと頼れる道具になるでしょう。
Enjoy notebooks!
参考文献
学術論文:
- Rule+ (2018) "Exploration and Explanation in Computational Notebooks"(CHI 2018): GitHub上の約123万件のノートブック分析、学術ノートブックの質的分析、データ分析者へのインタビュー
- Rule+ (2019) "Ten Simple Rules for Writing and Sharing Computational Analyses in Jupyter Notebooks"(PLOS Computational Biology): 再現可能なノートブックのための10のルールを提案する実践ガイド
- Pimentel+ (2019) "A Large-scale Study about Quality and Reproducibility of Jupyter Notebooks"(MSR 2019): GitHub上の約116万件のノートブックを対象にした品質・再現性の大規模調査
- Samuel & Mietchen (2024) "Computational Reproducibility of Jupyter Notebooks from Biomedical Publications"(GigaScience): 査読済み生物医学論文に付随する約2.7万件のノートブックの再現性調査
その他:
- Joel Grus (2018) "I Don't Like Notebooks": JupyterConでの講演。ノートブックが助長する悪い習慣を批判
- Joel Grus (2019) "If Not Notebooks, Then What? - Thoughts on notebooks and reproducibility": 上記の続編。AAAI 2019 Workshop on Reproducible AIにて、代替アプローチを議論
- JetBrains (2020) "We Downloaded 10,000,000 Jupyter Notebooks from GitHub — This Is What We Learned": 約972万件のノートブックの分析
- Agrawal (2024) "Lessons learned reinventing the Python notebook": marimo作者による設計哲学の解説
- Meyers+ (2025) "Why Stanford scientists needed a new Python notebook": SLAC国立加速器研究所の計算科学者による、Jupyterからmarimoへの移行の実践報告