做网站空间不给账号密码网站建设模板可用吗
做网站空间不给账号密码,网站建设模板可用吗,百度联盟网站一定要备案吗,网站规划的案例Python统计可视化实战#xff1a;从Friedman检验到Nemenyi检验的完整图表绘制指南
在算法性能比较、模型评估或任何需要对比多个方法在多个数据集上表现的场景中#xff0c;仅仅报告平均精度或误差是远远不够的。我们常常需要回答一个更根本的问题#xff1a;这些观察到的性…Python统计可视化实战从Friedman检验到Nemenyi检验的完整图表绘制指南在算法性能比较、模型评估或任何需要对比多个方法在多个数据集上表现的场景中仅仅报告平均精度或误差是远远不够的。我们常常需要回答一个更根本的问题这些观察到的性能差异究竟是算法本身能力所致还是仅仅源于数据集的随机波动这时非参数统计检验特别是Friedman检验及其后续的Nemenyi检验就成了数据科学家和研究人员的得力工具。然而冰冷的p值和检验统计量对于大多数读者甚至包括一些评审而言是抽象且难以直观理解的。将统计检验的结果转化为一张清晰、专业、可直接用于论文或报告的图表不仅能提升研究的可信度更能高效地传达核心结论。今天我们就深入探讨如何用Python的Matplotlib库将Friedman检验与Nemenyi检验的结果从一串数字变成一幅具有发表级质量的统计可视化图表。我们将超越简单的代码复制深入理解图表每一个元素背后的统计含义并掌握高度定制化的技巧让你的图表既能通过严格的学术审查又能贴合团队或项目的独特风格需求。1. 理解核心Friedman与Nemenyi检验在可视化中的角色在动手写代码之前我们必须厘清这两个检验分别回答了什么问题以及它们在可视化图表中对应哪些视觉元素。这决定了我们绘图时的逻辑框架。Friedman检验是一种非参数的双因素方差分析它用于判断多个相关样本例如多个算法在同一个数据集集合上的性能是否来自同一分布。其零假设是所有算法的性能无显著差异。如果Friedman检验拒绝了零假设通常p值 0.05我们只能说“至少有一个算法与其他算法不同”但并不知道具体是哪些算法之间存在差异。注意Friedman检验的结果通常是p值本身并不直接体现在我们最终要绘制的“CD图”上但它是进行后续两两比较如Nemenyi检验的前提。只有Friedman检验显著后续的两两比较才有意义。这时就需要Nemenyi检验或其它事后检验如Bonferroni-Dunn登场。Nemenyi检验用于在所有算法之间进行两两比较以找出具体哪些配对之间存在显著差异。其核心产出是一个叫做**临界域Critical Difference, CD**的值。这个CD值就是我们图表中那些“横线”长度的决定因素。可视化逻辑我们通常绘制的是“平均秩图”Average Ranks Plot有时直接被称为“CD图”。其核心组件包括Y轴列出所有参与比较的算法名称。X轴表示“平均秩”Average Rank。对于每个数据集算法性能最好如误差最小的排名为1次之为2以此类推。然后对所有数据集的排名求平均得到每个算法的平均秩。平均秩越小代表算法整体性能越优。散点每个算法在图中对应一个点其横坐标就是该算法的平均秩。横线CD线以每个算法的散点为中心向左向右各延伸CD/2的距离形成一条线段。如果两条算法的横线CD线没有重叠则表明这两个算法在Nemenyi检验下存在统计显著性差异。理解了这个逻辑我们就知道代码的每一部分在“画”什么以及为何要那样画。2. 构建基础图表从数据到图形的完整流程让我们从一个最基础的例子开始逐步构建图表。假设我们比较了四种算法Alg_A, Alg_B, Alg_C, Alg_D在15个数据集上的性能并已经计算出了它们的平均秩和Nemenyi检验的CD值。首先准备数据和基础绘图。import matplotlib.pyplot as plt import numpy as np # 模拟数据四种算法的平均秩 algorithm_names [Alg_A, Alg_B, Alg_C, Alg_D] average_ranks [1.8, 3.2, 2.1, 3.9] # 值越小越好 # Nemenyi检验计算出的临界域值 critical_difference 0.85 # 计算CD线的一半长度用于向左右延伸 cd_half critical_difference / 2 # 创建图形和坐标轴 fig, ax plt.subplots(figsize(10, 6)) # Y轴位置为每个算法分配一个整数位置方便绘图 y_positions np.arange(len(algorithm_names)) # 绘制散点每个算法的平均秩 ax.scatter(average_ranks, y_positions, s120, colorblack, markero, zorder5) # 绘制CD线以每个散点为中心的水平线段 for i, (rank, y) in enumerate(zip(average_ranks, y_positions)): line_x [rank - cd_half, rank cd_half] line_y [y, y] ax.plot(line_x, line_y, k-, linewidth3, solid_capstyleround, zorder4) # 设置Y轴刻度标签为算法名称 ax.set_yticks(y_positions) ax.set_yticklabels(algorithm_names, fontsize14) # 设置X轴标签和范围 ax.set_xlabel(Average Rank, fontsize16) ax.set_xlim(0.5, 4.5) # 根据平均秩范围适当调整 # 添加网格线便于观察置于底层 ax.grid(True, axisx, linestyle--, alpha0.7, zorder0) ax.set_axisbelow(True) # 添加标题 ax.set_title(Algorithm Comparison: Friedman-Nemenyi Test, fontsize18, pad20) plt.tight_layout() plt.show()这段代码生成了一个清晰的基础图表。现在任何读者都能一眼看出Alg_A的平均秩最低性能可能最好Alg_D的最高。通过观察CD线是否重叠可以初步判断例如Alg_A和Alg_D的线段完全没有重叠暗示它们之间存在显著差异。而Alg_B和Alg_C的线段有部分重叠意味着在当前显著性水平下它们的差异可能不显著。3. 深度定制打造出版级质量的统计图表基础图表可用但离“精美”和“完全符合要求”还有距离。学术图表通常有严格的格式要求项目报告也可能需要匹配特定的视觉主题。下面我们从多个维度进行深度定制。3.1 视觉样式与美学优化黑白打印的论文需要高对比度彩色报告则可以借助颜色传递更多信息。颜色与形状用颜色区分算法类别如传统方法 vs 深度学习方法。# 定义颜色和形状 colors [#2E86AB, #A23B72, #F18F01, #C73E1D] # 一组协调的色卡 markers [o, s, ^, D] # 圆形、方形、上三角、菱形 fig, ax plt.subplots(figsize(10, 6)) for i, (rank, y) in enumerate(zip(average_ranks, y_positions)): # 绘制带颜色的散点 ax.scatter(rank, y, s150, colorcolors[i], edgecolorblack, linewidth1.5, markermarkers[i], zorder5, labelalgorithm_names[i]) # 绘制CD线颜色与散点匹配但降低透明度 line_x [rank - cd_half, rank cd_half] line_y [y, y] ax.plot(line_x, line_y, colorcolors[i], linewidth4, alpha0.7, solid_capstyleround, zorder4) # 添加图例 ax.legend(locupper center, bbox_to_anchor(0.5, 1.15), ncol4, fontsize12, frameonTrue) # 优化脊柱边框和刻度 ax.spines[top].set_visible(False) ax.spines[right].set_visible(False) ax.spines[left].set_linewidth(1.2) ax.tick_params(axisboth, whichmajor, labelsize13) ax.set_xlabel(Average Rank, fontsize16, fontweightbold) ax.set_ylabel(Algorithm, fontsize16, fontweightbold)字体与排版使用更优雅的字体如LaTeX字体并统一字号。# 启用LaTeX文本渲染确保系统已安装LaTeX plt.rcParams.update({ text.usetex: False, # 如果环境支持LaTeX可设为True font.family: serif, font.serif: [Times New Roman, DejaVu Serif], font.size: 14 }) # 后续绘图代码... # 在设置标签时可以使用更丰富的文本格式 ax.set_title(r\textbf{Algorithm Performance Ranking}, fontsize18) # 使用粗体3.2 信息增强与注释一张好的图表应该尽可能自解释。添加显著性标注用星号或连线明确标出哪些配对差异显著。# 假设我们通过计算知道以下配对在Nemenyi检验下差异显著 significant_pairs [(Alg_A, Alg_D), (Alg_B, Alg_D)] # 在图表上方添加显著性标注的连线 def draw_significance_bar(ax, pair, y_positions_dict, x_range, bar_height0.1): 在图表上方绘制表示显著性的星号和横线 name1, name2 pair y1 y_positions_dict[name1] y2 y_positions_dict[name2] # 找到两个算法X轴位置平均秩的左右边界 x_left min(average_ranks[y1], average_ranks[y2]) - cd_half x_right max(average_ranks[y1], average_ranks[y2]) cd_half # 绘制横线 line_y max(y1, y2) bar_height * 3 # 在算法条上方一定距离 ax.plot([x_left, x_right], [line_y, line_y], k-, linewidth1.5, clip_onFalse) # 绘制两端的小竖线 ax.plot([x_left, x_left], [line_y-0.02, line_y], k-, linewidth1.5, clip_onFalse) ax.plot([x_right, x_right], [line_y-0.02, line_y], k-, linewidth1.5, clip_onFalse) # 添加星号 ax.text((x_left x_right) / 2, line_y 0.05, *, hacenter, vabottom, fontsize16, fontweightbold) # 创建算法名到Y位置的映射 y_pos_dict {name: pos for name, pos in zip(algorithm_names, y_positions)} # 绘制所有显著配对 for pair in significant_pairs: draw_significance_bar(ax, pair, y_pos_dict, ax.get_xlim())添加CD值说明在图表角落用文本框清晰注明CD值及显著性水平。# 在图表右下角添加文本说明 textstr fCD {critical_difference:.2f}\n($\\alpha 0.05$) props dict(boxstyleround, facecolorwheat, alpha0.8) ax.text(0.98, 0.02, textstr, transformax.transAxes, fontsize12, verticalalignmentbottom, horizontalalignmentright, bboxprops)3.3 输出与适配性最终图表需要适配各种输出场景论文PDF、幻灯片、网页等。高分辨率保存这是发表的基本要求。output_filename friedman_nemenyi_plot formats [png, pdf, svg] # 同时保存多种格式 for fmt in formats: plt.savefig(f{output_filename}.{fmt}, dpi600, # PNG格式分辨率 bbox_inchestight, # 紧凑边框去除多余白边 pad_inches0.1, # 保留少量内边距 facecolorwhite, # 确保背景为白色 edgecolornone ) print(fSaved to {output_filename}.{fmt})创建可复用的绘图函数将整个流程封装成一个函数方便在不同项目中调用。def plot_friedman_nemenyi(algorithm_names, average_ranks, cd_value, sig_pairsNone, figsize(10,6), styledefault): 绘制Friedman-Nemenyi检验的平均秩图CD图。 参数 ---------- algorithm_names : list of str 算法名称列表。 average_ranks : list of float 与算法名称顺序对应的平均秩列表。 cd_value : float Nemenyi检验的临界域值。 sig_pairs : list of tuple, optional 显著差异的算法配对列表如 [(Alg1, Alg2), ...]。 figsize : tuple, optional 图形尺寸默认(10,6)。 style : str, optional 图形样式可选 default, print黑白优化, color。 返回 ------- fig, ax : matplotlib图形和坐标轴对象 # 基于样式选择配置 if style print: colors [black] * len(algorithm_names) markers [o] * len(algorithm_names) line_style {color: black, alpha: 0.8} elif style color: colors plt.cm.Set3(np.linspace(0, 1, len(algorithm_names))) # 使用色彩映射 markers [o, s, ^, D, v, , , p, *, h] line_style {alpha: 0.6} else: # default colors [#2E86AB, #A23B72, #F18F01, #C73E1D, #6A994E] markers [o, s, ^, D, v] line_style {} fig, ax plt.subplots(figsizefigsize) y_pos np.arange(len(algorithm_names)) cd_half cd_value / 2 # 绘图核心循环 for idx, (rank, y) in enumerate(zip(average_ranks, y_pos)): color colors[idx % len(colors)] marker markers[idx % len(markers)] # 画点 ax.scatter(rank, y, s140, c[color], edgecolorsk, linewidth1, markermarker, zorder5) # 画CD线 ax.plot([rank - cd_half, rank cd_half], [y, y], colorcolor, linewidth3.5, zorder4, **line_style) # 坐标轴设置 ax.set_yticks(y_pos) ax.set_yticklabels(algorithm_names, fontsize13) ax.set_xlabel(Average Rank, fontsize15) ax.grid(True, axisx, linestyle:, alpha0.5) ax.set_axisbelow(True) # 添加CD值标注 ax.text(0.95, 0.05, fCD {cd_value:.2f}, transformax.transAxes, fontsize12, haright, vabottom, bboxdict(boxstyleround,pad0.3, facecolorlightgray, alpha0.8)) # 如果有显著配对添加标注 if sig_pairs: # 这里可以调用之前定义的 draw_significance_bar 函数 pass plt.tight_layout() return fig, ax # 使用示例 fig, ax plot_friedman_nemenyi(algorithm_names, average_ranks, critical_difference, stylecolor) plt.show()4. 实战进阶处理复杂场景与常见陷阱在实际研究中情况往往比示例更复杂。以下是几个常见挑战及其解决方案。场景一算法数量众多10个当算法很多时Y轴会变得拥挤CD线可能大量重叠导致图表难以阅读。解决方案增大图形尺寸将figsize调整为更宽的尺寸例如(14, 10)。横向绘图交换X轴和Y轴让算法名称在Y轴垂直方向平均秩在X轴水平方向。这通常能更好地利用空间。分组与颜色如果算法可以分类如基于树的、基于神经网络的、传统的使用颜色组和子图来呈现。交互式可视化考虑使用Plotly或Bokeh库创建交互式图表允许用户悬停查看详细信息或缩放局部区域。场景二平均秩非常接近当算法性能伯仲之间时所有平均秩可能挤在一个很小的范围内例如1.0到1.5CD线会很长导致图表X轴尺度不合理所有CD线几乎覆盖整个轴。解决方案调整X轴范围不要使用默认范围手动设置ax.set_xlim()使其紧密围绕平均秩的分布区间并留出足够空间显示CD线。重点标注如果差异微小考虑在图表中插入一个“放大镜”子图inset_axes来清晰展示关键区域的CD线重叠情况。from mpl_toolkits.axes_grid1.inset_locator import inset_axes # 在主图基础上创建插图 ax_main ... # 主坐标轴 # 定义插图区域在主图坐标系内 ax_inset inset_axes(ax_main, width40%, height30%, locupper right, bbox_to_anchor(0.1, 0.1, 0.9, 0.9), bbox_transformax_main.transAxes) # 在ax_inset上重新绘制平均秩非常接近的那几个算法并设置合适的xlim和ylim进行放大场景三与统计计算流程无缝集成理想情况下我们不希望手动计算平均秩和CD值而是希望从统计检验的结果中自动获取。解决方案利用scipy.stats进行Friedman检验并使用scikit-posthocs库进行Nemenyi事后检验。然后直接从结果对象中提取数据用于绘图。import numpy as np import scipy.stats as stats import scikit_posthocs as sp # 假设 performance_data 是一个 (n_datasets, n_algorithms) 的数组 # 每一行是一个数据集每一列是一个算法的性能指标如错误率 performance_data np.random.rand(15, 4) # 示例随机数据 # 1. 计算秩在每个数据集内对算法进行排名 ranks np.apply_along_axis(stats.rankdata, 1, performance_data) # 注意rankdata给最小的值赋秩1。如果你的指标是“越大越好”如准确率可能需要先取负值。 # 2. 计算平均秩 average_ranks np.mean(ranks, axis0) # 3. 执行Friedman检验 friedman_stat, friedman_p stats.friedmanchisquare(*performance_data.T) # 需要解包转置 print(fFriedman检验统计量: {friedman_stat:.3f}, p值: {friedman_p:.4f}) # 4. 如果Friedman检验显著p 0.05进行Nemenyi事后检验 if friedman_p 0.05: # scikit-posthocs 期望数据是 (n_algorithms, n_datasets) 的格式 nemenyi_result sp.posthoc_nemenyi_friedman(performance_data.T) print(Nemenyi检验两两比较p值矩阵:) print(nemenyi_result) # 从nemenyi_result中可以识别出显著的对并可能根据公式计算CD值 # CD q_alpha * sqrt( k*(k1) / (6*N) )其中q_alpha来自学生化范围统计k是算法数N是数据集数 # 一些库如Orange3直接提供CD计算。提示scikit-posthocs库返回的是p值矩阵。要获得CD值你可能需要查阅统计教材或使用其他专门包如Orange3中的compute_CD函数来计算或者根据检验原理自行实现。将计算流程与绘图函数结合可以实现从原始数据到发表级图表的“一键生成”。绘制Friedman-Nemenyi检验图表的真正价值在于它迫使研究者将统计推断的严谨性与视觉传达的有效性结合起来。我最初只是照搬网上的代码片段生成的图表勉强能用但在投稿时屡次被评审指出图表不专业或信息不完整。后来我花了时间深入理解每个参数的意义——为什么CD线要那样画坐标轴范围如何影响结论的呈现颜色和标注如何引导读者的注意力这个过程不仅提升了图表的颜值更重要的是加深了我对统计检验本身的理解。现在每当完成一组实验对比我都很享受这个从数据到洞察、再到清晰可视化的完整流程。它不再是一个枯燥的步骤而是讲述算法故事的最后也是最有力的一环。