多指标方案优选、工艺参数优化、综合评价……灰色关联分析(GRA)都能轻松搞定。本文不仅讲清楚原理,还附上一份可直接运行的Python代码,内含顶刊风格图表,帮你一键完成计算与可视化。一、什么是灰色关联分析?
灰色关联分析(Grey Relational Analysis, GRA)是灰色系统理论中的一种多因素决策方法。它的核心思想是:通过比较各方案与“理想最优方案”在几何形状上的相似程度,来判断方案的优劣。关联度越大,方案越优。
适用场景:
农业试验中不同处理组合的综合评价
工艺参数(温度、时间、浓度等)的多指标优化
供应商选择、项目评估等小样本决策问题
优点:
对样本量要求低(≥3即可)
不要求数据服从特定分布
计算过程透明,可解释性强
二、代码功能速览
下面这份完整的Python代码实现以下功能:
读取Excel数据,按处理组合分组求均值
执行完整的灰色关联分析(标准化→参考序列→关联系数→关联度→排名)
将所有中间计算过程导出到Excel(6张工作表)
生成4张专业图表(排名柱状图、交互热力图、指标箱线图、关联系数热图)
图表样式可定制:热力图改为绿色渐变,箱线图改为双色渐变+缺口箱体
代码保存路径:E:\DataAnalysis\GRA(自动创建)
三、完整代码与逐段解读
🧩 0. 导入所需库
import osimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom matplotlib.colors import LinearSegmentedColormap
🗂️ 1. 路径设置
input_path = r"E:\DataAnalysis\Data.xlsx"save_dir = r"E:\DataAnalysis\GRA"os.makedirs(save_dir, exist_ok=True)os.makedirs(os.path.join(save_dir, "plots"), exist_ok=True)
指定输入Excel路径和输出文件夹,自动创建目录。你需要修改 input_path 为自己的文件路径。
🎨 2. 自定义配色方案
代码中定义了三种渐变色,用于不同图表:
# --- 粉色系渐变(薄雾粉→晶石紫)---pink_palette = [ "#F9EDF4", # 薄雾粉 "#EDC9DD", # 樱花粉 "#E0A5C7", # 蔷薇粉 "#D180B1", # 胭脂粉 "#C15B9B", # 浆果紫 "#B02F86" # 晶石紫]custom_pink_cmap = LinearSegmentedColormap.from_list("custom_pink", pink_palette, N=256)# --- 绿色系单色渐变(森林绿→晨雾白绿)---green_palette = [ "#D4E7CF", # 晨雾白绿 "#B8D8B0", # 薄荷雾绿 "#9CC891", # 嫩苗绿 "#7FB873", # 新叶绿 "#61A855" # 森林绿]custom_green_cmap = LinearSegmentedColormap.from_list("custom_green", green_palette, N=256)# --- 双色渐变(森林绿→浆果红)---dual_palette = [ "#61A855", # 森林绿 "#7FB873", # 新叶绿 "#9CC891", # 嫩苗绿 "#B8D8B0", # 薄荷雾绿 "#D4E7CF", # 晨雾白绿 "#FFD6D4", # 贝壳粉 "#FFBAB8", # 蜜桃粉 "#FE9E9D", # 珊瑚粉 "#F98082", # 草莓红 "#F36069" # 浆果红]custom_dual_cmap = LinearSegmentedColormap.from_list("custom_dual", dual_palette, N=256)
可以根据需要修改这些十六进制颜色值,调出专属配色。
⚙️ 3. 全局绘图风格设置
plt.rcParams.update({ "font.family": ["Arial", "SimHei"], "font.size": 10, "axes.titlesize": 12, "axes.labelsize": 11, "xtick.labelsize": 9, "ytick.labelsize": 9, "legend.fontsize": 9, "figure.dpi": 300, "savefig.dpi": 600, "savefig.bbox": "tight", "axes.spines.top": False, "axes.spines.right": False, "grid.alpha": 0.3, "grid.linestyle": "--", "axes.unicode_minus": False})
中英文字体兼容(Arial + SimHei)
高分辨率输出(600 dpi),符合期刊要求
去掉顶部和右侧边框,网格线半透明虚线,更现代
📥 4. 读取数据
df = pd.read_excel(input_path, sheet_name="Sheet1")df_mean = df.groupby(["Treatment", "Factor1", "Factor2"]).mean().reset_index()indicators = [col for col in df_mean.columns if col not in ["Treatment", "Factor1", "Factor2"]]data_matrix = df_mean[indicators].valuestreatments = df_mean["Treatment"].valuesT = df_mean["Factor1"].valuesW = df_mean["Factor2"].values
假设Excel包含以下列:
代码先按三个分组变量求均值(若没有重复测量,均值即原值),然后提取指标矩阵和标签。
🧮 5. 灰色关联分析核心函数
def gray_relation_analysis(data, rho=0.5): data_norm = (data - data.min(axis=0)) / (data.max(axis=0) - data.min(axis=0) + 1e-8) ref = data_norm.max(axis=0) diff = np.abs(data_norm - ref) min_diff = diff.min() max_diff = diff.max() gamma = (min_diff + rho * max_diff) / (diff + rho * max_diff) grade = gamma.mean(axis=1) return data_norm, ref, diff, gamma, grade
参数解释:
rho:分辨系数,通常取0.5,用于调节关联系数之间的差异。
标准化方法:极差归一化,使各指标范围变为[0,1]。
参考序列:取每个指标归一化后的最大值(若指标越小越好,可将max改为min)。
关联系数:公式为 (min_diff + ρ·max_diff) / (diff + ρ·max_diff),反映每个方案每个指标与最优值的接近程度。
关联度:每个方案所有指标关联系数的算术平均值。
调用函数,并按照关联度降序排序:
data_norm, ref_seq, diff_matrix, gamma_matrix, gray_grade = gray_relation_analysis(data_matrix)rank_idx = np.argsort(gray_grade)[::-1]sorted_treat = treatments[rank_idx]sorted_grade = gray_grade[rank_idx]sorted_T = T[rank_idx]sorted_W = W[rank_idx]
📎 6. 导出完整计算过程到Excel
with pd.ExcelWriter(os.path.join(save_dir, "GRA_计算全过程.xlsx"), engine="openpyxl") as writer: df_mean.to_excel(writer, sheet_name="1_原始均值数据", index=False) pd.DataFrame(data_norm, columns=indicators, index=treatments).to_excel(writer, sheet_name="2_标准化数据") pd.DataFrame(ref_seq, index=indicators, columns=["最优参考序列"]).to_excel(writer, sheet_name="3_参考序列") pd.DataFrame(diff_matrix, columns=indicators, index=treatments).to_excel(writer, sheet_name="4_差异矩阵") pd.DataFrame(gamma_matrix, columns=indicators, index=treatments).to_excel(writer, sheet_name="5_关联系数矩阵") result_df = pd.DataFrame({ "排名": range(1, len(sorted_treat)+1), "处理组合": sorted_treat, "Factor1(T)": sorted_T, "Factor2(W)": sorted_W, "灰色关联度": np.round(sorted_grade, 4) }) result_df.to_excel(writer, sheet_name="6_关联度最终排名", index=False)
一张Excel内包含6个工作表,从原始数据到最终排名一目了然,方便论文附录或同行复核。
📊 7. 绘图(重点:样式定制)
图1:关联度排名柱状图
plt.figure(figsize=(10, 6))bar_colors = sns.color_palette(pink_palette, n_colors=len(sorted_treat))bars = plt.barh(sorted_treat[::-1], sorted_grade[::-1], color=bar_colors[::-1], height=0.7, edgecolor="white", linewidth=0.5)plt.barh(sorted_treat[0], sorted_grade[0], color="#61A855", height=0.7, label=f'最优组合:{sorted_treat[0]}')plt.xlabel("灰色关联度", fontweight="bold")plt.ylabel("处理组合", fontweight="bold")plt.title("各处理组合灰色关联度排名", fontweight="bold", pad=12)plt.xlim(left=np.min(sorted_grade)*0.9, right=np.max(sorted_grade)*1.05)plt.grid(axis='x')plt.legend(frameon=False)plt.tight_layout()plt.savefig(os.path.join(save_dir, "plots", "01_关联度排名柱状图.png"))plt.close()
图2:T×W交互热力图
heat_data = pd.DataFrame({"T": T, "W": W, "灰色关联度": gray_grade})heat_pivot = heat_data.pivot_table(index="T", columns="W", values="灰色关联度", aggfunc="mean")plt.figure(figsize=(8, 6))# 仅修改cmap为绿色系单色渐变,其余参数完全不变ax = sns.heatmap(heat_pivot, annot=True, cmap=custom_green_cmap, fmt=".4f", linewidths=0.8, linecolor="white", cbar_kws={"label": "灰色关联度"})plt.title("T×W处理组合关联度热力图", fontweight="bold", pad=12)ax.set_xlabel("Factor2 (W)", fontweight="bold")ax.set_ylabel("Factor1 (T)", fontweight="bold")plt.tight_layout()plt.savefig(os.path.join(save_dir, "plots", "02_TW交互热力图.png"))plt.close()
图3:各指标关联系数箱线图
plt.figure(figsize=(12, 6))# 核心修改:# 1. palette改为双色渐变# 2. notch=True 开启顶刊流行的缺口箱体(展示中位数置信区间,更专业美观)# 3. 优化箱体线条、宽度、异常值样式,提升质感sns.boxplot( data=gamma_matrix, palette=dual_palette, notch=True, # 缺口箱体 linewidth=1.2, # 箱体描边加粗 width=0.7, # 箱体宽度优化 fliersize=4, # 异常值点大小 flierprops={ "marker": "o", "markerfacecolor": "#B02F86", "markeredgecolor": "white", "alpha": 0.8 })plt.xticks(ticks=range(len(indicators)), labels=[f"Ind{i+1}" for i in range(len(indicators))], rotation=45)plt.xlabel("测量指标", fontweight="bold")plt.ylabel("关联系数", fontweight="bold")plt.title("各指标关联系数分布", fontweight="bold", pad=12)plt.tight_layout()plt.savefig(os.path.join(save_dir, "plots", "03_指标关联系数箱线图.png"))plt.close()
图4:关联系数矩阵热图
plt.figure(figsize=(14, 8))gamma_df = pd.DataFrame(gamma_matrix, index=treatments, columns=[f"Ind{i+1}" for i in range(len(indicators))])ax = sns.heatmap(gamma_df, annot=True, cmap=custom_pink_cmap, fmt=".3f", linewidths=0.5, linecolor="white", cbar_kws={"label": "关联系数"})plt.title("关联系数矩阵热图", fontweight="bold", pad=12)ax.set_xlabel("测量指标", fontweight="bold")ax.set_ylabel("处理组合", fontweight="bold")plt.tight_layout()plt.savefig(os.path.join(save_dir, "plots", "04_关联系数矩阵热图.png"))plt.close()
📢 8. 控制台输出结果
print("="*60)print("✅ 灰色关联分析完成!所有文件已自动保存")print(f"📂 文件保存路径:{save_dir}")print("="*60)print(f"🏆 最优处理组合:{sorted_treat[0]}")print(f"📊 最优组合关联度:{round(sorted_grade[0], 4)}")print("="*60)print("📋 关联度前5名组合:")for i in range(5): print(f"第{i+1}名:{sorted_treat[i]} | 关联度:{round(sorted_grade[i], 4)}")print("="*60)print("🖼️ 图表调整说明:")print(" 1. 02_TW交互热力图 → 森林绿单色渐变")print(" 2. 03_指标关联系数箱线图 → 双色渐变+顶刊流行缺口箱体")print("="*60)
三、总结
✅ 开箱即用:只需准备一张Excel表,修改路径即可运行
✅ 过程透明:所有中间结果导出到Excel,便于核查
✅ 图表精美:顶刊风格配色、缺口箱体、高分辨率输出
✅ 高度可定制:颜色、分辨系数、指标方向均可轻松修改
无论你是科研人员、数据分析师,还是学生,这套代码都能帮助你快速完成多指标方案优选任务。
赶快用你的代码和数据试试吧! 🚀
如果你觉得有帮助的话,欢迎点赞、收藏、转发!有任何问题或改进建议,也欢迎在评论区交流。