如何将含主列与子列的Excel表格转换为Pandas DataFrame以绘制图表
嘿,我懂你这种烦恼——带主列(参与者编号)和子列(测试类型)的Excel表格,直接用stack()处理会把数据拆得七零八落,行数暴增不说,结构还完全不适合后续画趋势图。我来给你调整一下处理流程,保证结果刚好符合你的绘图需求:
第一步:正确读取带复合表头的Excel
你之前读数据的时候,没告诉Pandas表格有两层表头(主列是参与者,子列是测试类型),导致后续stack乱了套。我们要指定用前两行作为多级列索引:
import pandas as pd # 读取Excel,指定前两行作为多级表头 DSAdf1 = pd.read_excel('dsa_for_clusters.xlsx', sheet_name="DSA", header=[0, 1])
这样Pandas会自动识别“参与者编号”和“测试类型”的层级关系,不会把表头当数据处理。
第二步:合并多级列名(可选,但更直观)
现在列名是多级的,比如(Participant1, TypeA),我们可以把它们合并成更易读的单一级列名,方便后续操作:
# 合并多级列名,格式为「参与者_测试类型」 DSAdf1.columns = ['_'.join(col).strip() for col in DSAdf1.columns.values]
这一步之后,列名就变成了Participant1_TypeA、Participant1_TypeB这种清晰的格式。
第三步:转换为适合绘图的长格式
用melt()代替单纯的stack(),它能精准控制哪些是固定的标识符列(比如Date),哪些是需要展开的测量列(各个参与者+测试类型的组合),不会产生冗余行:
# 转换为长格式:Date作为固定列,其他列展开为「参与者_类型」和「测试值」 df_long = DSAdf1.melt(id_vars=['Date'], var_name='Participant_Type', value_name='Test_Value')
现在的DataFrame结构是:Date | Participant_Type | Test_Value,已经比你之前的结果紧凑多了。
第四步:拆分列名,方便多维度筛选绘图
如果需要单独按“参与者”或“测试类型”筛选数据绘图,我们可以把Participant_Type拆成两列:
# 拆分「参与者_类型」列,得到独立的Participant和DSA_Type列 df_long[['Participant', 'DSA_Type']] = df_long['Participant_Type'].str.split('_', expand=True) # 删掉中间的Participant_Type列(可选) df_long = df_long.drop('Participant_Type', axis=1)
现在你的DataFrame结构就是完美的绘图格式:Date | Test_Value | Participant | DSA_Type,每一行对应一个日期下某个参与者的某类测试值,完全没有冗余数据。
为什么这个方法比你原来的stack()更好?
你之前用stack()会把所有层级的索引都展开,包括Date列的行索引,导致大量重复的行(比如同一个Date会被重复多次)。而melt()只展开你指定的测量列,保留Date作为固定的标识符,行数和原始Excel里的有效数据行数一致,完全符合你“容易处理并绘制不同类型测试值随时间变化曲线”的需求。
比如现在你可以轻松用Seaborn画每个参与者的各类测试值趋势图:
import seaborn as sns import matplotlib.pyplot as plt # 按参与者分组,绘制不同类型测试值的时间趋势 sns.lineplot(data=df_long, x='Date', y='Test_Value', hue='Participant', style='DSA_Type') plt.title('各类DSA测试值随时间变化趋势(按参与者分组)') plt.show()
备注:内容来源于stack exchange,提问作者Ghof-90




