Python Kano分析脚本修改:多特征合并为单图展示需求
解决Kano分析多特征合并绘图问题
当前脚本为每个特征生成单独图表,需求改为在单张图中展示所有特征的SI/DSI结果点,并通过图例标注每个特征名称。以下是修改后的完整代码及关键调整说明:
关键修改点
- 移除原单图绘制逻辑,改为先初始化全局画布,批量添加所有特征的散点
- 新增数据收集步骤,汇总所有特征的SI、DSI值及名称
- 统一设置图表样式、背景色块、双图例(Kano类别+特征名称),最后一次性保存并展示合并图
修改后的完整代码
# -*- coding: utf-8 -*- """ Spyder Editor 合并Kano分析所有特征到单张图 """ # 读取数据 import pandas as pd import matplotlib.pyplot as plt import numpy as np import collections import os from matplotlib.patches import Patch data = pd.read_excel(r'C:\Users\xxx\Nextcloud\03_Documents\xxx\data_kano.xlsx', header=0) # 修正原代码:drop操作需重新赋值才生效 data = data.drop(index=0) segment = list(range(0, len(data.columns)+1, 2)) store = [] for x in range(1, len(segment)): df = data.iloc[:, segment[x-1]:segment[x]].copy() store.append(df) # Kano分类矩阵 eval_matrix = pd.DataFrame( {'#1': ['Q','R','R','R','R'], '#2': ['A','I','I','I','R'], '#3': ['A','I','I','I','R'], '#4': ['A','I','I','I','R'], '#5': ['O','M','M','M','Q']}, index=['#1','#2','#3','#4','#5'] ) # 计算每个特征的Kano分类结果 result = pd.DataFrame() for x in range(0, len(store)): Kano_score = [] for y in range(len(store[x].iloc[:,0])): Kano_score.append(eval_matrix.loc[store[x].iloc[y,0], store[x].iloc[y,1]]) pos_col = f'Feature {x+1}-1' neg_col = f'Feature {x+1}-2' res_col = f'Feature {x+1}-Result' result[pos_col] = store[x].iloc[:,0].copy() result[neg_col] = store[x].iloc[:,1].copy() result[res_col] = Kano_score # 满意度/不满意度系数计算函数 def SI(A: int, O: int, M: int, I: int) -> float: return float((A + O) / (A + O + M + I)) def DSI(A: int, O: int, M: int, I: int) -> float: return float((O + M) / (A + O + M + I) * -1) # 汇总所有特征的SI、DSI值,同时导出Excel结果 feature_metrics = [] pos_cols = list(range(2, len(result.columns), 3)) os.makedirs('figures', exist_ok=True) with pd.ExcelWriter('Kano_scoring_Ergebnisse.xlsx', engine="openpyxl") as writer: for idx, col in enumerate(pos_cols): feature_name = f'Feature {idx+1}' count = collections.Counter(result.iloc[:, col]) df = pd.DataFrame.from_dict(count, orient='index', columns=['Score']) # 处理缺失类别,默认计数为0 A = df.loc['A', 'Score'] if 'A' in df.index else 0 O = df.loc['O', 'Score'] if 'O' in df.index else 0 M = df.loc['M', 'Score'] if 'M' in df.index else 0 I = df.loc['I', 'Score'] if 'I' in df.index else 0 si_val = SI(A, O, M, I) dsi_val = DSI(A, O, M, I) df['SI'] = np.nan df['DSI'] = np.nan df.loc['A', 'SI'] = si_val df.loc['A', 'DSI'] = dsi_val df.to_excel(writer, sheet_name=feature_name) feature_metrics.append((feature_name, si_val, dsi_val)) # 绘制合并图 plt.figure(figsize=(10, 8)) ax = plt.axes() # 绘制Kano分区背景色块 # 无差异区(蓝色) plt.fill([0.0,0.0,0.5,0.5], [-0.0,-0.5,-0.5,-0.0], alpha=0.25, color="b") # 魅力区(深绿) plt.fill([0.5,0.5,1.0,1.0], [-0.0,-0.5,-0.5,-0.0], alpha=0.25, color="#036630") # 一维区(黄色) plt.fill([0.5,0.5,1.0,1.0], [-0.5,-1.0,-1.0,-0.5], alpha=0.25, color="y") # 必备区(红色) plt.fill([0.0,0.0,0.5,0.5], [-0.5,-1.0,-1.0,-0.5], alpha=0.25, color="r") # 绘制所有特征的散点,自动分配差异化颜色 colors = plt.cm.tab10(np.linspace(0, 1, len(feature_metrics))) for (name, si, dsi), color in zip(feature_metrics, colors): ax.scatter(si, dsi, color=color, label=name, s=80, zorder=5) # 设置图表基础样式 ax.set(xlim=[0,1], ylim=[-1,0], xlabel='Functional (Satisfaction Coefficients CS+)', ylabel='Disfunctional (Dissatisfaction Coefficients CS-)', xticks=np.arange(0,1,0.1), yticks=np.arange(-1,0,0.1)) ax.set_title('Kano Analysis: All Features', size=16) ax.grid(True) # 加粗中间十字分隔线 gridlines = ax.yaxis.get_gridlines() gridlines[5].set_color('k') gridlines[5].set_linewidth(2.5) gridlines = ax.xaxis.get_gridlines() gridlines[5].set_color('k') gridlines[5].set_linewidth(2.5) # 添加双图例:Kano分区类别 + 特征名称 category_patches = [ Patch(color="b", alpha=0.25, label="Indifferent"), Patch(color="#036630", alpha=0.25, label="Attractive"), Patch(color="y", alpha=0.25, label="One-Dimensional"), Patch(color="r", alpha=0.25, label="Must Be") ] first_legend = ax.legend(handles=category_patches, bbox_to_anchor=(0.225, -0.3, 0.55, 0.5), loc='lower center', ncol=2, fontsize="small", framealpha=1) ax.add_artist(first_legend) ax.legend(loc='upper right', fontsize="small", title="Features") plt.tight_layout() plt.savefig('./figures/All_Features_Kano.jpg', bbox_inches='tight') plt.show()
额外修正说明
- 修复原代码中
data.drop(index=0)未赋值导致首行未删除的问题 - 处理部分特征缺失Kano类别计数的情况,避免KeyError
- 使用
tab10调色板自动为每个特征分配独特颜色,提升辨识度 - 优化图例布局,同时展示Kano分区和特征名称,避免重叠遮挡
内容的提问来源于stack exchange,提问作者Karl Winter
相关产品推荐
相关产品推荐

