论文党福音:用Python一键批量绘制YOLO系列算法PR曲线对比图(附完整代码)
在目标检测算法的论文写作中,性能对比是不可或缺的关键环节。PR曲线作为衡量检测精度的重要可视化工具,往往需要针对不同算法变体进行批量绘制和对比。传统手动绘制方式不仅耗时耗力,还难以保证图表风格的一致性。本文将介绍一套基于Python的自动化解决方案,帮助研究者快速生成符合学术出版要求的PR曲线对比图。
1. 环境准备与数据格式解析
1.1 基础环境配置
确保已安装以下Python库,这些是数据处理和可视化的核心工具:
pip install matplotlib numpy对于需要支持学术论文常用字体的用户,建议额外安装Times New Roman字体文件。在Windows系统中,该字体通常已预装;Linux用户可通过以下命令获取:
sudo apt install ttf-mscorefonts-installer1.2 理解YOLO结果文件结构
典型的YOLO系列算法输出的results.txt文件包含以下关键信息:
98.50% = echinus AP Precision: [0.985,0.984,0.983,...,0.901] Recall: [0.001,0.002,0.003,...,1.000]文件结构解析:
- AP值:表示平均精度(Average Precision)
- Precision数组:对应不同置信度阈值下的精确率
- Recall数组:对应不同置信度阈值下的召回率
2. 核心代码实现与定制化
2.1 数据提取与处理模块
以下代码实现了从results.txt文件中提取并格式化PR数据的功能:
import re from typing import Dict, List def parse_results_file(file_path: str) -> Dict[str, List[List[float]]]: """ 解析YOLO结果文件,返回{class_name: [precision_list, recall_list]}的字典 """ with open(file_path, 'r') as f: content = f.read() pattern = re.compile( r'(\d+\.\d+)% = (\w+) AP\nPrecision: \[(.*?)\]\nRecall: \[(.*?)\]' ) results = {} for match in pattern.finditer(content): ap, class_name, prec_str, recall_str = match.groups() precision = list(map(float, prec_str.split(','))) recall = list(map(float, recall_str.split(','))) results[class_name] = [precision, recall] return results2.2 多算法对比配置
创建config.py文件集中管理算法配置:
# 算法名称列表(按需修改) ALGORITHMS = [ 'YOLOv5s', 'YOLOv5m', 'YOLOv5l', 'YOLOv5x', 'YOLOv8n', 'YOLOv8s', 'YOLOX', 'OurMethod' ] # 颜色配置(支持HEX/RGB/颜色名称) COLOR_MAP = { 'YOLOv5s': '#FF6347', # Tomato 'YOLOv5m': '#4682B4', # SteelBlue 'YOLOv5l': '#32CD32', # LimeGreen 'YOLOv5x': '#9932CC', # DarkOrchid 'YOLOv8n': '#FFD700', # Gold 'YOLOv8s': '#FF69B4', # HotPink 'YOLOX': '#20B2AA', # LightSeaGreen 'OurMethod': '#000000' # Black }3. 高级可视化技巧
3.1 学术级图表美化
import matplotlib.pyplot as plt from matplotlib import font_manager def setup_academic_style(): """配置学术论文要求的图表样式""" plt.style.use('seaborn-whitegrid') font_path = '/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf' # 字体配置 font_prop = font_manager.FontProperties( fname=font_path, size=12 ) plt.rcParams.update({ 'font.family': font_prop.get_name(), 'axes.titlesize': 14, 'axes.labelsize': 12, 'xtick.labelsize': 10, 'ytick.labelsize': 10, 'legend.fontsize': 10, 'figure.dpi': 300, 'savefig.bbox': 'tight' })3.2 多子图布局示例
def plot_multiclass_pr(algorithm_data: Dict[str, Dict], output_path: str): """ 绘制多类别PR曲线对比图 algorithm_data: {alg_name: {class_name: [precision, recall]}} """ setup_academic_style() classes = list(next(iter(algorithm_data.values())).keys()) n_cols = min(3, len(classes)) n_rows = (len(classes) + n_cols - 1) // n_cols fig, axes = plt.subplots(n_rows, n_cols, figsize=(6*n_cols, 4*n_rows)) axes = axes.flatten() if isinstance(axes, np.ndarray) else [axes] for ax, class_name in zip(axes, classes): for alg_name, data in algorithm_data.items(): precision = data[class_name][0] recall = data[class_name][1] ax.plot(recall, precision, label=alg_name, color=COLOR_MAP[alg_name], linewidth=1.5) ax.set_title(class_name) ax.set_xlabel('Recall') ax.set_ylabel('Precision') ax.set_xlim(0, 1) ax.set_ylim(0, 1) # 统一图例 handles, labels = ax.get_legend_handles_labels() fig.legend(handles, labels, loc='lower center', ncol=4, bbox_to_anchor=(0.5, -0.05)) plt.tight_layout() plt.savefig(output_path, dpi=300, bbox_inches='tight')4. 批量处理与自动化
4.1 文件组织规范
推荐的项目目录结构:
├── config.py ├── pr_plotter.py ├── results/ │ ├── YOLOv5s.txt │ ├── YOLOv5m.txt │ ├── ... └── outputs/ ├── class1.png ├── class2.png ├── ...4.2 主程序集成
from pathlib import Path from typing import Dict, List import config def batch_process(results_dir: str = 'results', output_dir: str = 'outputs'): """批量处理results目录下的所有结果文件""" algorithm_data = {} for alg_name in config.ALGORITHMS: file_path = Path(results_dir) / f"{alg_name}.txt" if file_path.exists(): algorithm_data[alg_name] = parse_results_file(file_path) # 创建输出目录 Path(output_dir).mkdir(exist_ok=True) # 生成对比图 plot_multiclass_pr(algorithm_data, Path(output_dir)/'pr_comparison.png') # 单独保存每个类别的PR曲线 first_alg = next(iter(algorithm_data.keys())) for class_name in algorithm_data[first_alg].keys(): plot_single_class_pr(algorithm_data, class_name, Path(output_dir)/f'{class_name}_pr.png') if __name__ == '__main__': batch_process()4.3 实用技巧与注意事项
- 曲线平滑处理:对于波动较大的PR曲线,可添加Savitzky-Golay滤波:
from scipy.signal import savgol_filter def smooth_curve(data: List[float], window_size: int = 5) -> List[float]: return savgol_filter(data, window_size, 2)性能优化:当处理大量算法对比时(>10种),建议:
- 使用不同的线型(虚线、点线等)辅助区分
- 分组展示(如将YOLOv5系列与YOLOv8系列分开对比)
- 添加主要AP值标注在曲线旁
期刊特殊要求:
- IEEE系列期刊通常要求矢量图格式(.eps/.pdf)
- Nature系列期刊偏好特定字体大小(通常不小于8pt)
- Springer系列期刊对图例位置有明确规范