使用 python pandas style.where (或其他方式)为不匹配的两列中的特定单元格着色并导出到 excel

Colour specific cells from two columns that don't match, using python pandas style.where (or otherwise) and export to excel

我想为不匹配的两列中的特定单元格着色,但想将其与 python pandas style.where 一起使用并导出到 excel 使用 openpyxl.

到目前为止我的代码:

df = pd.DataFrame({
    'config_dummy1': ["dummytext"] * 100,
    'config_size_x': ["textstring"] * 100,
    'config_size_y': ["textstring"] * 100,
    'config_dummy2': ["dummytext"] * 100
})
df.at[50, 'config_size_x'] = "xandydontmatch"
df.at[99, 'config_size_y'] = "xandydontmatch"
print(df)
df.style.where(
    df['config_size_x'] != df['config_size_y'],
    'color: #ffffff; background-color: #ba3018',
    other=''
).to_excel('styled.xlsx', engine='openpyxl')

我卡住了,因为它产生了一个错误:

Traceback (most recent call last):
  File "python-match-csv.py", line 205, in <module>
    main2()
  File "python-match-csv.py", line 131, in main2
    ).to_excel('styled.xlsx', engine='openpyxl')
  File "F:\Python36\lib\site-packages\pandas\io\formats\style.py", line 175, in to_excel
    engine=engine)
  File "F:\Python36\lib\site-packages\pandas\io\formats\excel.py", line 652, in write
    freeze_panes=freeze_panes)
  File "F:\Python36\lib\site-packages\pandas\io\excel.py", line 1390, in write_cells
    for cell in cells:
  File "F:\Python36\lib\site-packages\pandas\io\formats\excel.py", line 617, in get_formatted_cells
    self._format_body()):
  File "F:\Python36\lib\site-packages\pandas\io\formats\excel.py", line 529, in _format_regular_rows
    for cell in self._generate_body(coloffset):
  File "F:\Python36\lib\site-packages\pandas\io\formats\excel.py", line 601, in _generate_body
    styles = self.styler._compute().ctx
  File "F:\Python36\lib\site-packages\pandas\io\formats\style.py", line 514, in _compute
    r = func(self)(*args, **kwargs)
  File "F:\Python36\lib\site-packages\pandas\io\formats\style.py", line 604, in _applymap
    result = self.data.loc[subset].applymap(func)
  File "F:\Python36\lib\site-packages\pandas\core\frame.py", line 6072, in applymap
    return self.apply(infer)
  File "F:\Python36\lib\site-packages\pandas\core\frame.py", line 6014, in apply
    return op.get_result()
  File "F:\Python36\lib\site-packages\pandas\core\apply.py", line 318, in get_result
    return super(FrameRowApply, self).get_result()
  File "F:\Python36\lib\site-packages\pandas\core\apply.py", line 142, in get_result
    return self.apply_standard()
  File "F:\Python36\lib\site-packages\pandas\core\apply.py", line 248, in apply_standard
    self.apply_series_generator()
  File "F:\Python36\lib\site-packages\pandas\core\apply.py", line 277, in apply_series_generator
    results[i] = self.f(v)
  File "F:\Python36\lib\site-packages\pandas\core\frame.py", line 6070, in infer
    return lib.map_infer(x.astype(object).values, func)
  File "pandas/_libs/src\inference.pyx", line 1472, in pandas._libs.lib.map_infer
  File "F:\Python36\lib\site-packages\pandas\io\formats\style.py", line 671, in <lambda>
    return self.applymap(lambda val: value if cond(val) else other,
TypeError: ("'Series' object is not callable", 'occurred at index config_dummy1')

TypeError: ("'Series' 对象不可调用", 'occurred at index config_dummy1'

我对 .where() 以外的建议持开放态度,我也尝试过使用 .apply() 但失败了。

注意:列索引位置不固定,可以是config_size_x, config_dummy1, config_dummy2, config_size_y或者任意组合

注 2:如果重要,请使用 windows 和 python 3.6

您可以使用 apply 创建样式 DataFrame:

def color(x):
    c1 = 'color: #ffffff; background-color: #ba3018'
    m = x['config_size_x'] != x['config_size_y']
    df1 = pd.DataFrame('', index=x.index, columns=x.columns)
    df1.loc[m, ['config_size_x', 'config_size_y']] = c1
    return df1

df.style.apply(color, axis=None)

一般解决方案:

df = pd.DataFrame({
    'config_dummy1': ["dummytext"] * 10,
    'a_y': ["a"] * 10,
    'config_size_x': ["textstring"] * 10,
    'config_size_y': ["textstring"] * 10,
    'config_dummy2': ["dummytext"] * 10,
    'a_x': ["a"] * 10
})
df.at[5, 'config_size_x'] = "xandydontmatch"
df.at[9, 'config_size_y'] = "xandydontmatch"
df.at[0, 'a_x'] = "xandydontmatch"
df.at[3, 'a_y'] = "xandydontmatch"
print(df)

def color(x):
    c1 = 'color: #ffffff; background-color: #ba3018'
    df1 = pd.DataFrame('', index=x.index, columns=x.columns)

    #select only columns ends with _x and _y and sorting
    cols = sorted(x.filter(regex='_x$|_y$').columns)
    #loop by pairs and assign style by mask
    for i, j in zip(cols[::2],cols[1::2]):
        #pairs columns 
        #print (i, j)
        m = x[i] != x[j]
        df1.loc[m, [i, j]] = c1
    return df1

df.style.apply(color, axis=None).to_excel('styled.xlsx', engine='openpyxl')

因为这个问题被标记为 styleframe:

from StyleFrame import StyleFrame, Styler

df = pd.DataFrame({'a': [1, 2], 'b': [1, 3]})

sf = StyleFrame(df)
sf.apply_style_by_indexes(sf[sf['a'] != sf['b']], styler_obj=Styler(bg_color='red'))
sf.to_excel('test.xlsx').save()

会产生

如果您只想为不匹配行的子集着色,您可以简单地使用 cols_to_style 参数:

sf.apply_style_by_indexes(sf[sf['a'] != sf['b']], styler_obj=Styler(bg_color='red'),
                          cols_to_style=['a', 'b'])