将 Pandas Styler 应用于 MultiIndex 列表

Posted

技术标签:

【中文标题】将 Pandas Styler 应用于 MultiIndex 列表【英文标题】:Apply Pandas Styler to MultiIndex list 【发布时间】:2021-02-12 23:59:53 【问题描述】:

我有一个多索引数据透视表,我正在从数据框制作如下所示:

pivot_summary = pd.pivot_table(df, index=['Team', 'Associate Name'], columns=['Date'], values=['Call Transfers'], aggfunc=sum, fill_value=0, margins=True, margins_name='Grand Total')

然后我有一个名为“SubTotals”的函数,它计算每个团队的总数并将它们添加到多索引中的第 1 级。

def SubTotals(df):
    '''
    The purpose of this function is to add sub-totals to each individual team 
    '''
    #create a dataframe with the totals of each team
    sub_totals = df.sum(level=0)
    #create variable that stores string of team # + 'Total'
    sub_totals_str = sub_totals.index.str[:] + ' Total'
    
    #add the subtotals for each team to the main dataframe
    final_df = df.append(sub_totals.assign(Team=sub_totals_str).set_index('Team', append=True)).sort_index()
    
    #drop the duplicate "Grand-Total" row at the bottom
    final_df.drop(final_df.tail(1).index, inplace=True)
    
    #create string variables of both index(Multi-level index) to zip into tuples
    index_level_0 = sub_totals.index.tolist()
    index_level_1 = sub_totals_str.tolist()
    
    #remove duplicate "Grand Total" from second index
    index_level_1[-1] = ''     
    
    #zip index to pass through formatting function
    team_totals_index = list(zip(index_level_0,index_level_1))
    
    return final_df, team_totals_index

到目前为止,一切都很好,我得到了每个团队的小计,这正是我想要的。我卡住的地方是我想突出显示“teams_totals_index”变量中的所有行。我正在尝试创建一个函数“highlight_rows”,它将多索引列表作为参数并在匹配时突出显示。我见过很多使用 lambda 代替的示例,它已作为粗略的检查,例如:final_df.style.apply(lambda x: ['background: lightgreen' if x.name==('Grand Total','') else '' for i in x], axis=1)

产生我正在寻找的结果,它完全突出显示多索引('Grand Total','')行,但我也想突出所有其他团队。我不想将每个索引硬编码到 lambda 函数中,因为团队的数量是动态的。

我曾尝试使用 lambda 函数来创建我自己的示例,但我没有成功。以下是我尝试过的。

def highlight_rows(x, index_list):
    '''
    highlight the maximum Totals of each team and Grand Total.
    '''
    df_styler = x.copy()
    
    b_color = 'background: lightgreen'
    
    for index_0, index_1 in index_list:
        df_styler.loc[index_0, index_1] = b_color
        
    return df_styler

然后我尝试申请final_df.style.apply(highlight_rows, index_list=team_totals_index, axis=1)

但我得到一个 ValueError:长度不匹配,预期值 32,新轴有 22 个元素

我也试过了:

def highlight_rows(x, index_list):
    '''
    highlight the maximum Totals of each team and Grand Total.
    '''
    
      
    for index_0, index_1 in index_list:
        if x.name== (index_0, index_1):
            return ['background: lightgreen']
        else:
            return ''

但我也收到相同的 ValueError:长度不匹配,预期值 1 个元素,新值有 22 个元素。

基本上我想遍历我的列表“total_teams_index”,其中包含我想要突出显示的多级索引。任何关于我如何实现这一点的见解将不胜感激。

【问题讨论】:

【参考方案1】:

虽然我似乎无法将其构建为一个函数并使其工作,但我找到了一个可行的解决方案,而无需对每个索引对进行硬编码。我正在使用方法链按照文档的建议逐段构建样式。

final_df.style.\
    apply(lambda x: ['background-color: #FF9900'
                     if x.name in team_totals_index else 'background-color:#FFCC99' for i in x], axis=1).\
    apply(lambda x: ['font-weight: bold' if x.name in team_totals_index else '' for i in x], axis=1).\
    apply(lambda x: ['border-top-style:solid' if x.name in team_totals_index else '' for i in x], axis=1).\
    apply(lambda x: ['border-bottom-style:solid' if x.name in team_totals_index else '' for i in x], axis=1)

我个人不喜欢重复使用同一个循环,但它符合我的目的,并且完全按照需要设置所有样式。让所有这些工作的关键是if x.name in [list containing index pairs],而不是像上面的示例中所示尝试迭代每个索引对。我希望这可以帮助任何遇到并且仍然可以使用一种不那么冗长/功能友好的方式来构建它的人。

【讨论】:

以上是关于将 Pandas Styler 应用于 MultiIndex 列表的主要内容,如果未能解决你的问题,请参考以下文章

具有多索引的 Pandas 样式对象

Multi-Groupby(迭代或应用函数)

Pandas表格美颜技巧

12大Pandas配置技巧

12大Pandas配置技巧

Pandas样式的默认浮动格式