pandas retain styling when reformatting cells - without reparsing string to numbers

自古美人都是妖i 提交于 2021-01-29 09:02:01

问题


For a pandas data frame of:

I want to reformat it to:

However, the styling is lost. How can I retain the styling whilst reformatting? Instead, formatting after the fact would also be fine. But parsing the string to numbers to validate styling conditions seems complicated as the number of digits is not constant.

It was constructed by:

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

回答1:


I found solution, idea is return DataFrame of styles and then use Styler.apply for another modified 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')

Another idea, similar:

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)


来源:https://stackoverflow.com/questions/60588197/pandas-retain-styling-when-reformatting-cells-without-reparsing-string-to-numb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!