【问题标题】:pandas retain styling when reformatting cells - without reparsing string to numberspandas 在格式化单元格时保留样式 - 无需将字符串解析为数字
【发布时间】:2020-03-08 13:54:17
【问题描述】:

对于熊猫数据框:

我想将其重新格式化为:

但是,样式丢失了。如何在重新格式化时保留样式? 相反,事后格式化也可以。但是将字符串解析为数字以验证样式条件似乎很复杂,因为数字的数量不是恒定的。

它的建造者:

import pandas as pd
import numpy as np

df_source = pd.DataFrame({'foo': [['0.001', '0.001', '0.190'], ['0.220', '0.029', '0.000'], ['-0.754', '0.202', '0.000'], ['-0.393', '0.191', '0.042']], 
                  'bar': [['-9.076', '2.548', '0.001'], ['7.111', '2.461', '0.005'], ['-35.263', '13.918', '0.013'], ['-0.393', '0.191', '0.042']], 'feature': ['first', 'second', '3rd', '4th']})
df_source.index = df_source.feature
df_source = df_source.drop(['feature'], axis=1)

def highlight_significant(x, sign_level_1, sign_level_2):
    if x is np.nan:
        return ''
    else:
        if isinstance(x, list):
            p_value = float(x[2])
            if float(x[0]) > 0:
                if p_value < sign_level_2:
                    return 'font-weight: bold;background-color: lightgreen'
                elif p_value < sign_level_1:
                    color = 'lightgreen'
                    return 'background-color: %s' % color
                else:
                    return ''
            else:
                if p_value < sign_level_2:
                    return 'font-weight: bold;background-color: yellow'
                elif p_value < sign_level_1:
                    color = 'yellow'
                    return 'background-color: %s' % color
                else:
                    return ''
        else:
            return ''
df_source = df_source.style.applymap(highlight_significant, sign_level_1=0.05, sign_level_2=0.01)
display(df_source)


# various variants are calculated, now combine selected metrics
df_summary = pd.DataFrame({'feature':[], 'foo': [], 'bar':[]})
# print(df_summary.iloc[0])

def format_results(r):
    if len(r)> 1:
        coefficient = r[0]
        std_err = r[1]
        return f'{round(float(coefficient), 2)} ({round(float(std_err), 2)})'
    else:
        # handle empty
        return '-'

d = df_source.data
def construct_record(name, column, index, df):
    df.loc[index] = [name] +  \
    [format_results(d.foo[column])] + \
    [format_results(d.bar[column])]
    return df

df_summary = construct_record('Descriptive name 1', 'first', 0, df_summary)
df_summary = construct_record('Descriptive name 2', 'second', 1, df_summary)
df_summary.index = df_summary.feature
df_summary = df_summary.drop(['feature'], axis=1)
df_summary

【问题讨论】:

    标签: python pandas styling


    【解决方案1】:

    我找到了解决方案,想法是返回DataFrame of styles,然后使用Styler.apply 进行另一个修改DataFrame

    #removed styles
    styles = df_source.applymap(lambda x: highlight_significant(x, sign_level_1=0.05, sign_level_2=0.01))
    print (styles)
                                                    foo  \
    feature                                               
    first                                                 
    second    font-weight: bold;background-color: green   
    3rd      font-weight: bold;background-color: yellow   
    4th                        background-color: yellow   
    
                                                    bar  
    feature                                              
    first    font-weight: bold;background-color: yellow  
    second    font-weight: bold;background-color: green  
    3rd                        background-color: yellow  
    4th                        background-color: yellow 
    
    df = df_source.applymap(lambda x: f'{x[0]}({round(float(x[1]), 2)})')
    print (df)
                      foo             bar
    feature                              
    first      0.001(0.0)    -9.076(2.55)
    second    0.220(0.03)     7.111(2.46)
    3rd       -0.754(0.2)  -35.263(13.92)
    4th      -0.393(0.19)    -0.393(0.19)
    
    #styler need function, so used lambda
    df.style.apply(lambda x: styles, axis=None).to_excel('file.xlsx')
    

    另一个想法,类似:

    styles = lambda x: df_source.applymap(lambda x: highlight_significant(x, sign_level_1=0.05, sign_level_2=0.01))
    print (styles)
    <function <lambda> at 0x000000000DEF21F8>
    
    df = df_source.applymap(lambda x: f'{x[0]}({round(float(x[1]), 2)})')
    print (df)
    
    df.style.apply(styles, axis=None).to_excel('file.xlsx')
                      foo             bar
    feature                              
    first      0.001(0.0)    -9.076(2.55)
    second    0.220(0.03)     7.111(2.46)
    3rd       -0.754(0.2)  -35.263(13.92)
    4th      -0.393(0.19)    -0.393(0.19)
    

    【讨论】:

    • format_results中构造新行后是否也可以保留样式?原因是:我有多个来自各种回归运行的df_source。现在选择所需的数据点并重新格式化它们(在创建结果字符串之前)是否可以在行上定义样式?
    • @GeorgHeiler - 我认为不是,必须相同的索引,两者中的列。
    • 那么对于这种情况,我需要使用正则表达式将结果字符串解析为两个数字,然后根据需要应用样式?还是有更简单的方法?
    • @GeorgHeiler - 我认为不容易。因为styles 有很多限制。但是如果以某种方式返回由样式填充的 DataFrame(具有与新 DataFrame 相同的大小),则解决方案有效。问题应该是如何创建这个数据框,我认为
    • 所以首先选择(但保留所有 3 个值),然后重新格式化并保持样式
    猜你喜欢
    • 2018-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-10
    • 1970-01-01
    • 2011-02-09
    • 1970-01-01
    相关资源
    最近更新 更多