如何从项目根目录分块运行Python脚本并整合Jupyter Notebook以避免重复工作
解决脚本全量执行与Notebook代码同步的实用方案
你目前遇到的「脚本一次性全流程执行、Notebook与py文件代码重复」的问题,其实是数据科学项目里很常见的痛点,下面给你几个针对性的解决方案,按需选择即可:
方案1:让Jupyter Notebook直接复用项目模块(彻底告别代码复制)
不用把Notebook里的分析代码手动复制到train.py,直接在Notebook里导入项目的src模块,实现交互式分析和代码复用:
- 在
notebook目录下创建一个setup_notebook.py(或者直接在Notebook开头添加这段代码):
import sys from pathlib import Path # 将项目根目录加入Python路径,解决模块导入问题 project_root = Path(__file__).parent.parent sys.path.append(str(project_root))
- 之后在Notebook里就能直接调用项目中的模块:
from src.utils.general_imports import * from src.utils.dataset import csv_to_dataframe # 交互式测试数据加载逻辑 train, test = csv_to_dataframe() print("数据预览:") print(train.head()) print(f"数据形状:{train.shape}") # 甚至可以直接调用train.py的main函数 from src.modelling.train import main main()
这样你在Notebook里做分析、调参,直接复用项目代码,不用重复编写;需要批量运行全流程时,依然用make train即可。
方案2:给train.py加命令行参数,实现分块执行
用argparse给train.py添加步骤参数,让你可以指定只运行某一部分流程(比如仅加载数据、仅训练模型),避免每次从头执行:
修改train.py:
from ..utils.general_imports import * from ..utils.dataset import * import argparse def load_data(): train, test = csv_to_dataframe() print("Taking a glance at the dataframe") print(train.head()) print("Shape of the dataframe:", train.shape) return train, test def preprocess_data(train, test): # 你的预处理逻辑 pass def train_model(train): # 你的模型训练逻辑 pass def main(): parser = argparse.ArgumentParser(description="Run specific steps of the training pipeline") parser.add_argument("--step", choices=["load", "preprocess", "train", "all"], default="all", help="Which pipeline step to execute") args = parser.parse_args() train, test = None, None if args.step in ["load", "preprocess", "train", "all"]: train, test = load_data() if args.step in ["preprocess", "train", "all"]: train, test = preprocess_data(train, test) if args.step in ["train", "all"]: train_model(train) if __name__ == '__main__': main()
然后修改Makefile,支持传递参数:
train: src/modelling/train.py python -m src.modelling.train --step $(step) # 示例用法: # 仅加载数据:make train step=load # 全流程执行:make train
这样你可以按需执行某一步骤,不用每次都从头跑完全流程。
方案3:用缓存机制跳过重复计算
如果痛点是「数据加载/预处理太耗时」,可以给中间结果加缓存,下次运行直接读取缓存文件:
比如用joblib缓存DataFrame:
from joblib import dump, load from pathlib import Path def load_data(): cache_dir = Path("data/cache") cache_dir.mkdir(exist_ok=True) cache_path = cache_dir / "train_test_data.joblib" if cache_path.exists(): print("Loading cached data...") return load(cache_path) else: print("Loading data from CSV...") train, test = csv_to_dataframe() dump((train, test), cache_path) return train, test
第一次运行会生成缓存文件,后续执行直接读取缓存,大幅节省重复运行的时间。
方案4:用nbconvert将Notebook转成可执行脚本
如果还是习惯在Notebook里写全流程代码,可以用nbconvert直接把Notebook转成符合项目结构的py文件,不用手动调整导入:
# 将Notebook转成脚本,输出到src/modelling目录 jupyter nbconvert --to script notebook/your_analysis.ipynb --output-dir src/modelling/ --output train.py
如果需要先执行Notebook再转脚本,可以加--execute参数:
jupyter nbconvert --execute --to script notebook/your_analysis.ipynb --output-dir src/modelling/ --output train.py
这个方法适合一次性生成脚本,频繁迭代分析的话还是方案1更高效。
内容的提问来源于stack exchange,提问作者Anon
相关产品推荐
相关产品推荐

