pandas 重新格式化单元格时保留样式 - 无需将字符串重新解析为数字
pandas retain styling when reformatting cells - without reparsing string to numbers
对于 pandas 数据帧:
我想将其重新格式化为:
但是,样式丢失了。如何在重新格式化时保留样式?
相反,事后格式化也可以。但是将字符串解析为数字以验证样式条件似乎很复杂,因为位数不是常数。
它的构建者是:
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
我找到了解决方案,想法是 return 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)
对于 pandas 数据帧:
我想将其重新格式化为:
但是,样式丢失了。如何在重新格式化时保留样式? 相反,事后格式化也可以。但是将字符串解析为数字以验证样式条件似乎很复杂,因为位数不是常数。
它的构建者是:
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
我找到了解决方案,想法是 return 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)