比较同一行中的多个列并突出显示 pandas 中的差异
Compare multiple columns within same row and highlight differences in pandas
我的数据框类似于:
NAME
DB1
DB2
DB3
DB4
WORKFLOW_1
workflow1-1.jar
workflow1-2.jar
workflow1-1.jar
workflow1-3.jar
WORKFLOW_2
workflow2-1.jar
workflow2-1.jar
workflow2-1.jar
workflow2-1.jar
WORKFLOW_3
workflow3-2.jar
workflow3-1.jar
workflow3-1.jar
workflow3-1.jar
WORKFLOW_4
workflow4-1.jar
其中 NAME 是整个 n 数据库中此 table 的键.我正在从特定列收集数据并将其并排合并以供进一步分析。
我的问题是我需要突出显示列之间包含不同文件名的行 DBn.
我试过以下解决方案:
def highlight(row):
for key1, column1 in row.items():
if key1 != 'NAME':
for key2, column2 in row.items():
if key2 != 'NAME':
if column1 != column2:
return ['background-color: red']
return ['background-color: green']
pd = pd.style.apply(highlight)
当至少有一个文件名与其他文件名不同时,我尝试对整行设置样式,但没有成功,当我导出到 excel 时,只有第一行是红色的,这不是均匀的应该发生的情况之一。
最简单(和幼稚)的方法是使用 Series.eq 针对第一个值测试每一行。设置合适的 subset
在这里非常重要,因为我们只想与其他相似值进行比较。
def highlight_row(s: pd.Series) -> List[str]:
bg_color = 'red'
if s.eq(s[0]).all():
bg_color = 'green'
return [f'background-color:{bg_color}'] * len(s)
df.style.apply(
func=highlight_row,
subset=['DB1', 'DB2', 'DB3', 'DB4'],
axis=1
)
在仅与过滤后的数组进行相等性比较之前,我们可以通过使用布尔索引从每一行中排除空字符串和空值(以及任何其他无效值)来减少一些天真:
def highlight_row(s: pd.Series) -> List[str]:
filtered_s = s[s.notnull() & ~s.eq('')]
# Check for completely empty row (prevents index error from filtered_s[0])
if filtered_s.empty:
# No valid values in row
css_str = ''
elif filtered_s.eq(filtered_s[0]).all():
# All values are the same
css_str = 'background-color: green'
else:
# Row Values Differ
css_str = 'background-color: red'
return [css_str] * len(s)
我们还可以利用 IndexSlice 更动态地 select subset
的列,而不是手动传递列名列表:
df.style.apply(
func=highlight_row,
subset=pd.IndexSlice[:, 'DB1':],
axis=1
)
最后,如果想要突出显示整行,可以将 idx/cols 传递给样式函数而不是子集化:
def highlight_row(s: pd.Series, idx: pd.IndexSlice) -> List[str]:
css_str = 'background-color: red'
# Filter Columns
filtered_s = s[idx]
# Filter Values
filtered_s = filtered_s[filtered_s.notnull() & ~filtered_s.eq('')]
# Check for completely empty row
if filtered_s.empty:
css_str = '' # Empty row Styles
elif filtered_s.eq(filtered_s[0]).all():
css_str = 'background-color: green'
return [css_str] * len(s)
df.style.apply(
func=highlight_row,
idx=pd.IndexSlice['DB1':], # 1D IndexSlice!
axis=1
)
设置和导入:
from typing import List
import pandas as pd # version 1.4.2
df = pd.DataFrame({
'NAME': ['WORKFLOW_1', 'WORKFLOW_2', 'WORKFLOW_3', 'WORKFLOW_4'],
'DB1': ['workflow1-1.jar', 'workflow2-1.jar', 'workflow3-2.jar', ''],
'DB2': ['workflow1-2.jar', 'workflow2-1.jar', 'workflow3-1.jar',
'workflow4-1.jar'],
'DB3': ['workflow1-1.jar', 'workflow2-1.jar', 'workflow3-1.jar', ''],
'DB4': ['workflow1-3.jar', 'workflow2-1.jar', 'workflow3-1.jar', '']
})
我的数据框类似于:
NAME | DB1 | DB2 | DB3 | DB4 |
---|---|---|---|---|
WORKFLOW_1 | workflow1-1.jar | workflow1-2.jar | workflow1-1.jar | workflow1-3.jar |
WORKFLOW_2 | workflow2-1.jar | workflow2-1.jar | workflow2-1.jar | workflow2-1.jar |
WORKFLOW_3 | workflow3-2.jar | workflow3-1.jar | workflow3-1.jar | workflow3-1.jar |
WORKFLOW_4 | workflow4-1.jar |
其中 NAME 是整个 n 数据库中此 table 的键.我正在从特定列收集数据并将其并排合并以供进一步分析。
我的问题是我需要突出显示列之间包含不同文件名的行 DBn.
我试过以下解决方案:
def highlight(row):
for key1, column1 in row.items():
if key1 != 'NAME':
for key2, column2 in row.items():
if key2 != 'NAME':
if column1 != column2:
return ['background-color: red']
return ['background-color: green']
pd = pd.style.apply(highlight)
当至少有一个文件名与其他文件名不同时,我尝试对整行设置样式,但没有成功,当我导出到 excel 时,只有第一行是红色的,这不是均匀的应该发生的情况之一。
最简单(和幼稚)的方法是使用 Series.eq 针对第一个值测试每一行。设置合适的 subset
在这里非常重要,因为我们只想与其他相似值进行比较。
def highlight_row(s: pd.Series) -> List[str]:
bg_color = 'red'
if s.eq(s[0]).all():
bg_color = 'green'
return [f'background-color:{bg_color}'] * len(s)
df.style.apply(
func=highlight_row,
subset=['DB1', 'DB2', 'DB3', 'DB4'],
axis=1
)
在仅与过滤后的数组进行相等性比较之前,我们可以通过使用布尔索引从每一行中排除空字符串和空值(以及任何其他无效值)来减少一些天真:
def highlight_row(s: pd.Series) -> List[str]:
filtered_s = s[s.notnull() & ~s.eq('')]
# Check for completely empty row (prevents index error from filtered_s[0])
if filtered_s.empty:
# No valid values in row
css_str = ''
elif filtered_s.eq(filtered_s[0]).all():
# All values are the same
css_str = 'background-color: green'
else:
# Row Values Differ
css_str = 'background-color: red'
return [css_str] * len(s)
我们还可以利用 IndexSlice 更动态地 select subset
的列,而不是手动传递列名列表:
df.style.apply(
func=highlight_row,
subset=pd.IndexSlice[:, 'DB1':],
axis=1
)
最后,如果想要突出显示整行,可以将 idx/cols 传递给样式函数而不是子集化:
def highlight_row(s: pd.Series, idx: pd.IndexSlice) -> List[str]:
css_str = 'background-color: red'
# Filter Columns
filtered_s = s[idx]
# Filter Values
filtered_s = filtered_s[filtered_s.notnull() & ~filtered_s.eq('')]
# Check for completely empty row
if filtered_s.empty:
css_str = '' # Empty row Styles
elif filtered_s.eq(filtered_s[0]).all():
css_str = 'background-color: green'
return [css_str] * len(s)
df.style.apply(
func=highlight_row,
idx=pd.IndexSlice['DB1':], # 1D IndexSlice!
axis=1
)
设置和导入:
from typing import List
import pandas as pd # version 1.4.2
df = pd.DataFrame({
'NAME': ['WORKFLOW_1', 'WORKFLOW_2', 'WORKFLOW_3', 'WORKFLOW_4'],
'DB1': ['workflow1-1.jar', 'workflow2-1.jar', 'workflow3-2.jar', ''],
'DB2': ['workflow1-2.jar', 'workflow2-1.jar', 'workflow3-1.jar',
'workflow4-1.jar'],
'DB3': ['workflow1-1.jar', 'workflow2-1.jar', 'workflow3-1.jar', ''],
'DB4': ['workflow1-3.jar', 'workflow2-1.jar', 'workflow3-1.jar', '']
})