如何为多层索引Pandas DataFrame列应用条件颜色样式
多层索引Pandas DataFrame条件着色适配方案
问题说明
- 已有可正常运行的单层索引DataFrame条件着色逻辑,需要适配新增一级
summary表头的MultiIndex列DataFrame,着色规则保持不变,仅新增一级顶部表头。 - 原单层索引DataFrame结构:
Value Limit Actual Issues < 33 0 Rating > 4 4.2 Complaints < 15 18 Time 30 - 45 41 Tip -- -
- 多层索引构造代码:
df.columns = pd.MultiIndex.from_product([['summary'], df.columns])
- 构造完成的多层索引DataFrame结构:
summary Value Limit Actual Issues < 33 0 Rating > 4 4.2 Complaints < 15 18 Time 30 - 45 41 Tip -- -
- 原单层索引用的着色函数直接运行会触发KeyError,尝试通过
pd.IndexSlice修改列引用未生效。原函数代码如下:
import re def highlight(row): numbers = re.findall('[0-9]+', row['Limit']) if row['Value'] in ('Issues','Rating','Complaints'): if '>' in row['Limit'] and row['Actual'] > numbers[0]: color = 'green' elif row['Actual'] < numbers[0]: color = 'green' else: color = 'red' else: if len(numbers) == 0: color = 'yellow' elif row['Actual'] > numbers[0] and row['Actual'] < numbers[1]: color = 'green' else: color = 'red' return f"background-color: {color}"
适配方案
核心问题是MultiIndex列按行遍历传入的行对象,索引为多层元组,直接传入二级列名无法匹配到对应字段;同时原函数存在逻辑缺口:未区分</>阈值符号、非数值行无异常处理、返回单一样式会给整行着色。
修改后完整可运行代码如下:
import pandas as pd import re # -------------------------- # 测试数据构造(已有df可跳过) # -------------------------- data = [ ["Issues", "< 33", 0], ["Rating", "> 4", 4.2], ["Complaints", "< 15", 18], ["Time", "30 - 45", 41], ["Tip", "--", "-"] ] df = pd.DataFrame(data, columns=["Value", "Limit", "Actual"]) df.columns = pd.MultiIndex.from_product([['summary'], df.columns]) # -------------------------- # 修改后的着色函数 # -------------------------- def highlight(row): # 多层列需传入完整层级元组取值 limit_val = row[('summary', 'Limit')] value_type = row[('summary', 'Value')] actual_val = row[('summary', 'Actual')] # 提取阈值数值 numbers = re.findall('[0-9]+', str(limit_val)) # 非数值Actual直接返回黄色背景 try: actual_num = float(actual_val) except (ValueError, TypeError): return ["", "", "background-color: yellow"] # 单阈值判断逻辑(Issues/Rating/Complaints行) if value_type in ('Issues','Rating','Complaints'): threshold = float(numbers[0]) if '>' in limit_val and actual_num > threshold: color = 'green' elif '<' in limit_val and actual_num < threshold: color = 'green' else: color = 'red' # 区间阈值判断逻辑(Time行) else: if len(numbers) < 2: color = 'yellow' low = float(numbers[0]) high = float(numbers[1]) color = 'green' if low < actual_num < high else 'red' # 返回长度与列数一致的样式列表,仅给Actual列加背景色 return ["", "", f"background-color: {color}"] # -------------------------- # 应用样式 # -------------------------- styled_df = df.style.apply(highlight, axis=1) # 在Jupyter类环境中直接渲染styled_df即可查看效果
关键修改点
- 列引用适配:所有行内字段取值改为传入完整多层列元组,解决KeyError问题。
- 逻辑补全:明确区分
</>阈值判断规则,修复原函数大于号场景下逻辑判断遗漏的问题。 - 异常兼容:增加Actual值转数值的异常捕获,适配Tip行这类无有效数值的场景。
- 样式返回优化:返回等长样式列表,仅给Actual列添加背景色,其余列保持默认样式,和预期效果完全一致。
内容的提问来源于stack exchange,提问作者moys
相关产品推荐
相关产品推荐

