pandas сохранить стиль при переформатировании ячеек - без разбора строки на числа - PullRequest
0 голосов
/ 08 марта 2020

Для pandas фрейма данных:

enter image description here

Я хочу переформатировать его в:

enter image description here

Однако стиль теряется. Как я могу сохранить стиль при переформатировании? Вместо этого форматирование после факта также было бы хорошо. Но синтаксический анализ строки с числами для проверки условий моделирования кажется сложным, поскольку число цифр не является постоянным.

Оно было построено с помощью:

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 Ответ

1 голос
/ 08 марта 2020

Я нашел решение, идея вернуть 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)
...