问题
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