[英]Best practices for turning jupyter notebooks into python scripts
Jupyter (iPython) notebook 是當之無愧地被稱為原型代碼和交互地執行各種機器學習東西的好工具。 但是當我使用它時,我不可避免地會遇到以下情況:
假設我已經在 jupyter 中開發了一個完整的機器學習管道,其中包括從各種來源獲取原始數據、清理數據、特征工程和訓練模型。 現在用高效可讀的代碼制作腳本的最佳邏輯是什么? 到目前為止,我曾經通過幾種方式解決它:
只需將 .ipynb 轉換為 .py,只需稍作更改,即可將筆記本中的所有管道硬編碼為一個 Python 腳本。
制作一個包含多個函數的腳本(大約,每個一兩個單元格一個函數),嘗試用單獨的函數組成管道的各個階段,並相應地命名它們。 然后通過argparse
指定所有參數和全局常量。
與第 (2) 點相同,但現在將所有函數包裝在類中。 現在所有全局常量以及每個方法的輸出都可以存儲為類屬性。
使用多個腳本將筆記本轉換為 python 模塊。 我沒有嘗試過,但我懷疑這是解決問題的最長方法。
我想,這種整體設置在數據科學家中很常見,但令人驚訝的是,我找不到任何有用的建議。
親們,請分享您的想法和經驗。 你有沒有遇到過這個問題? 你是怎么解決的?
救命稻草:在編寫筆記本時,逐步將代碼重構為函數,編寫一些最少的
assert
測試和文檔字符串。
之后,從 notebook 重構到腳本就很自然了。 不僅如此,即使您沒有計划將它們變成其他任何東西,它也能讓您在編寫長筆記本時生活更輕松。
具有“最少”測試和文檔字符串的單元格內容的基本示例:
def zip_count(f):
"""Given zip filename, returns number of files inside.
str -> int"""
from contextlib import closing
with closing(zipfile.ZipFile(f)) as archive:
num_files = len(archive.infolist())
return num_files
zip_filename = 'data/myfile.zip'
# Make sure `myfile` always has three files
assert zip_count(zip_filename) == 3
# And total zip size is under 2 MB
assert os.path.getsize(zip_filename) / 1024**2 < 2
print(zip_count(zip_filename))
一旦你將它導出到裸.py
文件,你的代碼可能還沒有被構建到類中。 但是值得努力重構你的 notebook 到它有一組記錄的函數,每個函數都有一組簡單的assert
語句,可以很容易地移動到tests.py
以便使用pytest
、 unittest
或其他你。 如果有意義的話,在那之后將這些函數捆綁到您的類的方法中是非常容易的。
如果一切順利,之后您需要做的就是編寫您的if __name__ == '__main__':
及其“鈎子”:如果您正在編寫由終端調用的腳本,您將需要處理命令-行參數,如果你正在編寫一個模塊,你會想 用__init__.py
文件等來考慮 它的 API 。
當然,這完全取決於預期的用例是什么:將筆記本轉換為小腳本與將其轉換為成熟的模塊或包之間存在很大差異。
以下是筆記本到腳本工作流程的一些想法:
print
語句、繪圖等。if __name__ == '__main__'
編寫腳本的入口。assert
語句分開,並在tests.py
中tests.py
一個最小的測試套件。我們有類似的問題。 然而,我們正在使用幾個筆記本來對結果進行原型設計,畢竟這些結果也應該成為幾個 python 腳本。
我們的方法是我們將代碼放在一邊,這些代碼在這些筆記本中不斷重復。 我們把它放到python模塊中,每個notebook都會導入這個模塊,在生產中也會用到。 我們不斷迭代改進這個模塊,並添加我們在原型設計過程中發現的測試。
Notebooks 變得很像配置腳本(我們只是簡單地將其復制到最終生成的 python 文件中)和一些我們在生產中不需要的原型檢查和驗證。
最重要的是,我們不害怕重構:)
我最近制作了一個模塊( NotebookScripter )來幫助解決這個問題。 它允許您通過函數調用來調用 jupyter notebook。 使用起來很簡單
from NotebookScripter import run_notebook
run_notebook("./path/to/Notebook.ipynb", some_param="Provided Exteranlly")
關鍵字參數可以傳遞給函數調用。 它很容易使筆記本電腦可從外部進行參數化。
在 .ipynb 單元格內
from NotebookScripter import receive_parameter
some_param = receive_parameter(some_param="Return's this value by default when matching keyword not provided by external caller")
print("some_param={0} within the invocation".format(some_param))
run_notebook() 支持 .ipynb 文件或 .py 文件——允許人們輕松使用 .py 文件,因為它可能由 vscode 的 ipython 的 nbconvert 生成。 您可以以對交互使用有意義的方式組織代碼,並在需要時在外部重用/自定義它。
您應該以小步驟分解邏輯,這樣您的管道將更容易維護。 由於您已經有一個工作代碼庫,您希望保持代碼運行,因此進行小的更改、測試和重復。
我會走這條路:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.