如何基于DataFrame的subtype列绘制Mann-Whitney U检验图并解决报错
解决Mann-Whitney U检验多组比较及绘图问题
问题概述
你作为Python统计新手,希望基于包含normal、KIRP、KIRC、KICH的subtype列,绘制Mann-Whitney U检验(Wilcoxon秩和检验)相关的箱线图,但现有代码触发类型错误,且后续逻辑存在问题。
报错原因分析
mannwhitneyu仅支持两样本比较:你直接传入4个DataFrame,导致第三个参数被误识别为use_continuity(要求布尔值),而实际传入的是DataFrame,触发TypeError: unhashable type: 'DataFrame'。- 多组U值计算逻辑错误:
U2 = nnormal*nkirp*nkirc*nkich - U1仅适用于两样本场景,多组无此公式。 - 绘图参数无效:
px.box(_, y="pnorm")中_不是有效数据框,pnorm也不是数据框列名,无法生成图表。
修正后的完整代码
以下代码实现两两Mann-Whitney U检验并绘制带显著性标记的箱线图(匹配你提供的示例图风格):
import pandas as pd import plotly.express as px import plotly.graph_objects as go from scipy.stats import mannwhitneyu from itertools import combinations # 假设df是你的原始数据集 # 1. 数据预处理:选择目标特征并转为长格式(以第一个特征列为例,可替换为具体列名) target_feature = df.columns[7] # 对应你代码中的iloc[:,7] plot_data = df[["subtype", target_feature]].rename(columns={target_feature: "expression"}) # 2. 执行两两Mann-Whitney U检验 groups = ["normal", "KIRP", "KIRC", "KICH"] pairwise_pvalues = [] # 生成所有组间两两组合,若仅需normal vs 肿瘤组,可替换为[("normal", "KIRP"), ("normal", "KIRC"), ("normal", "KICH")] for group_a, group_b in combinations(groups, 2): data_a = plot_data[plot_data["subtype"] == group_a]["expression"] data_b = plot_data[plot_data["subtype"] == group_b]["expression"] # 双侧检验,使用精确方法计算p值 _, p_val = mannwhitneyu(data_a, data_b, alternative="two-sided", method="exact") pairwise_pvalues.append({"group1": group_a, "group2": group_b, "p_value": p_val}) # 3. 绘制箱线图 fig = px.box( plot_data, x="subtype", y="expression", color="subtype", title=f"{target_feature} 在不同亚型中的分布(Mann-Whitney U检验)", labels={"expression": "表达量", "subtype": "亚型"} ) # 4. 添加显著性标记 y_upper = plot_data["expression"].max() * 1.1 # 标记起始位置 # 定义显著性规则 def sig_marker(p): if p < 0.001: return "***" elif p < 0.01: return "**" elif p < 0.05: return "*" else: return "ns" # 遍历检验结果,绘制连接线和标记 for idx, result in enumerate(pairwise_pvalues): # 获取两组在x轴的索引位置 x_idx1 = groups.index(result["group1"]) x_idx2 = groups.index(result["group2"]) sig = sig_marker(result["p_value"]) # 绘制连接两组的横线 fig.add_trace( go.Scatter( x=[x_idx1, x_idx1, x_idx2, x_idx2], y=[y_upper + idx*0.05*y_upper, y_upper + idx*0.05*y_upper + 0.02*y_upper, y_upper + idx*0.05*y_upper + 0.02*y_upper, y_upper + idx*0.05*y_upper], mode="lines", line=dict(color="black", width=1), showlegend=False ) ) # 添加显著性标记文本 fig.add_annotation( x=(x_idx1 + x_idx2)/2, y=y_upper + idx*0.05*y_upper + 0.02*y_upper, text=sig, showarrow=False, font=dict(size=12) ) # 调整y轴范围,确保标记完整显示 fig.update_layout(yaxis_range=[plot_data["expression"].min()*0.9, y_upper*1.2]) fig.show()
代码说明
- 数据格式转换:将宽格式数据转为长格式,符合Plotly箱线图的输入要求。
- 两两检验逻辑:使用
itertools.combinations生成所有组间组合,对每组执行Mann-Whitney U检验。若仅需比较正常组与肿瘤组,可直接指定组合列表。 - 显著性标记:根据p值大小生成对应星号标记,并在箱线图上方绘制连接线,清晰展示组间差异显著性。
- 批量处理扩展:若需对
iloc[:,7:-2]的所有特征批量绘图,可循环遍历列名,重复上述绘图逻辑。
内容的提问来源于stack exchange,提问作者melolilili
相关产品推荐
相关产品推荐

