今日的示例代码包含2个部分
知识点回顾
作业:尝试针对之前的心脏病项目ipynb,将他按照今天的示例项目整理成规范的形式,思考下哪些部分可以未来复用。
# 示例
import os
# 定义文件夹路径
folder_path = r'C:\Users\Name\Documents\Project\Files'
# 遍历文件夹中的文件
for index, filename in enumerate(os.listdir(folder_path)):
# 拆分文件名和后缀
file_ext = os.path.splitext(filename)[1] # 获取后缀(如 .txt)
new_name = f'report_{index + 1}{file_ext}' # 新文件名格式:report_1.txt
old_path = os.path.join(folder_path, filename)
new_path = os.path.join(folder_path, new_name)
os.rename(old_path, new_path) # 重命名文件
print(f"已重命名: {filename} → {new_name}")
说明
目标:为项目创建标准文件夹结构(如 data/, src/, logs/)。
# 示例
import os
# 项目根目录
project_root = r'C:\Users\Name\Documents\MyProject'
# 定义标准文件夹结构
folders = [
'data/raw',
'data/processed',
'src',
'src/models',
'src/utils',
'logs',
'docs',
'results'
]
# 创建文件夹(如果不存在)
for folder in folders:
path = os.path.join(project_root, folder)
os.makedirs(path, exist_ok=True) # exist_ok=True 避免重复创建报错
print(f"创建文件夹: {path}")
说明:
一个典型的机器学习项目通常包含以下阶段:
数据加载:从文件、数据库、API 等获取原始数据。
命名参考:load_data.py 、data_loader.py
数据探索与可视化:了解数据特性,初期可用 Jupyter Notebook,成熟后固化绘图函数。
命名参考:eda.py 、visualization_utils.py
数据预处理:处理缺失值、异常值,进行标准化、归一化、编码等操作。
命名参考:preprocess.py 、data_cleaning.py 、data_transformation.py
特征工程:创建新特征,选择、优化现有特征。
命名参考:feature_engineering.py
模型训练:构建模型架构,设置超参数并训练,保存模型。
命名参考:model.py 、train.py
模型评估:用合适指标评估模型在测试集上的性能,生成报告。
命名参考:evaluate.py
模型预测:用训练好的模型对新数据预测。
命名参考:predict.py 、inference.py
# 示例
from sklearn.model_selection import train_test_split
import pandas as pd
# 加载数据集
data = pd.read_csv('data/raw/iris.csv')
X = data.drop('target', axis=1) # 特征
y = data['target'] # 标签
# 拆分数据集(80% 训练,20% 测试)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 保存到文件
train_data = pd.concat([X_train, y_train], axis=1)
test_data = pd.concat([X_test, y_test], axis=1)
train_data.to_csv('data/processed/train.csv', index=False)
test_data.to_csv('data/processed/test.csv', index=False)
print("数据集已拆分并保存到 data/processed/ 目录")
说明:
目标:定义函数时使用 UTF-8 编码和类型注解。
# -*- coding: utf-8 -*-
from typing import List, Tuple, Dict
def process_data(numbers: List[float], threshold: float) -> Tuple[List[float], List[float]]:
"""
将数字列表分为大于阈值和小于等于阈值的两组。
参数:
numbers (List[float]): 输入的数字列表
threshold (float): 阈值
返回:
Tuple[List[float], List[float]]: 两个列表(大于阈值的列表,小于等于阈值的列表)
"""
above_threshold = [x for x in numbers if x > threshold]
below_threshold = [x for x in numbers if x <= threshold]
return above_threshold, below_threshold
# 示例用法
data: List[float] = [1.2, 3.4, 0.5, 4.6, 2.3]
threshold: float = 2.0
above, below = process_data(data, threshold)
print(f"大于 {threshold}: {above}")
print(f"小于等于 {threshold}: {below}")
说明:
编码格式:文件顶部添加 # -- coding: utf-8 -- 确保支持中文字符。
类型注解:
numbers: List[float]:参数类型注解。
-> Tuple[List[float], List[float]]:返回值类型注解。
使用 typing 模块定义复杂类型(如 List, Tuple, Dict)。
1. 项目结构设计
heart-disease-project/
├── config.py # 配置参数
├── data/ # 数据相关文件
│ ├── raw/ # 原始数据
│ └── processed/ # 预处理后的数据
├── models/ # 模型文件
├── src/ # 源代码
│ ├── data_processing.py # 数据处理
│ ├── model_training.py # 模型训练
│ ├── evaluation.py # 模型评估
│ └── utils.py # 通用工具函数
├── README.md # 项目说明
└── requirements.txt # 依赖库
mkdir -p heart-disease-project/data/{raw,processed}
mkdir -p heart-disease-project/models
mkdir -p heart-disease-project/src
touch heart-disease-project/config.py
touch heart-disease-project/README.md
touch heart-disease-project/requirements.txt
# config.py
import os
# 数据路径
RAW_DATA_PATH = os.path.join("data", "raw", "heart_disease.csv")
PROCESSED_DATA_PATH = os.path.join("data", "processed", "heart_data_processed.csv")
# 模型路径
MODEL_SAVE_PATH = os.path.join("models", "heart_model.pkl")
# 超参数
TEST_SIZE = 0.2
RANDOM_STATE = 42
# src/data_processing.py
import pandas as pd
from sklearn.model_selection import train_test_split
from config import RAW_DATA_PATH, PROCESSED_DATA_PATH
def load_and_preprocess_data():
# 加载原始数据
df = pd.read_csv(RAW_DATA_PATH)
# 处理缺失值(示例:填充均值)
df.fillna(df.mean(), inplace=True)
# 特征与标签分离
X = df.drop("target", axis=1)
y = df["target"]
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 保存预处理后的数据
processed_data = {
"X_train": X_train,
"X_test": X_test,
"y_train": y_train,
"y_test": y_test,
}
pd.to_pickle(processed_data, PROCESSED_DATA_PATH)
return processed_data
# src/model_training.py
import joblib
from sklearn.ensemble import RandomForestClassifier
from config import MODEL_SAVE_PATH
from src.data_processing import load_and_preprocess_data
def train_model():
# 加载预处理后的数据
data = pd.read_pickle(config.PROCESSED_DATA_PATH)
X_train, y_train = data["X_train"], data["y_train"]
# 初始化模型
model = RandomForestClassifier(n_estimators=100, random_state=42)
# 训练模型
model.fit(X_train, y_train)
# 保存模型
joblib.dump(model, MODEL_SAVE_PATH)
print(f"Model saved to {MODEL_SAVE_PATH}")
# src/evaluation.py
import joblib
from sklearn.metrics import classification_report, roc_auc_score
from config import MODEL_SAVE_PATH, PROCESSED_DATA_PATH
def evaluate_model():
# 加载模型和数据
model = joblib.load(MODEL_SAVE_PATH)
data = pd.read_pickle(PROCESSED_DATA_PATH)
X_test, y_test = data["X_test"], data["y_test"]
# 预测结果
y_pred = model.predict(X_test)
y_proba = model.predict_proba(X_test)[:, 1]
# 输出评估指标
print("Classification Report:")
print(classification_report(y_test, y_pred))
print("ROC AUC Score:")
print(roc_auc_score(y_test, y_proba))
# src/utils.py
import os
import logging
def create_directory(path):
"""确保目录存在"""
if not os.path.exists(path):
os.makedirs(path)
logging.info(f"Created directory: {path}")
# requirements.txt
pandas
scikit-learn
joblib
* 准备数据
将原始数据文件 heart_disease.csv 放入 data/raw/ 目录。
* 运行数据处理
python src/data_processing.py
* 训练模型
python src/model_training.py
* 评估模型
python src/evaluation.py
@浙大疏锦行