【问题标题】:Pandas: How to highlight a cell value based on a Z-score value?Pandas:如何根据 Z 值突出显示单元格值?
【发布时间】:2021-07-03 06:51:34
【问题描述】:

在我下面的df,我想:

  1. 使用 z 分数识别和标记 col_E 中的异常值
  2. 分别说明如何在两列或多列中使用 z 分数来识别和标记异常值,例如 col_Dcol_E

数据集见下文

import pandas as pd
from scipy import stats
  
# intialise data of lists
df = { 
         'col_A':['P0', 'P1', 'P2', 'P4', 'P5'],
         'col_B':[1,1,1,1,1],
         'col_C':[1,2,3,5,9],
         'col_D':[120.05, 181.90, 10.34, 153.10, 311.17],
        'col_E':[110.21, 191.12, 190.21, 12.00, 245.09 ],
        'col_F':[100.22,199.10, 191.13,199.99, 255.19],
        'col_G':[140.29, 291.07, 390.22, 245.09, 4122.62],
        
        }
  
# Create DataFrame
df = pd.DataFrame(df)
  
# Print the output.
df

期望:首先标记col_D 中的所有异常值,然后标记col_Dcol_E(注意:在我下面的图片中,10.3412.00 被随机突出显示)

第一季度

尝试:

#Q1
exclude_cols = ['col_A','col_B','col_C','col_D','col_F','col_G']
include_cols = ['col_E'] # desired column

def flag_outliers(s, exclude_cols):
    if s.name in exclude_cols:
        print(s.name)
        return '' 
    else:
        s=df[(np.abs(stats.zscore(df['col_E'])) > 3)] # not sure of this part of the code
        
        return ['background-color: yellow' if v else '' for v in indexes]

df.style.apply(lambda s: flag_outliers(s, exclude_cols), axis=1, subset=include_cols)



#Q2
exclude_cols = ['col_A','col_B','col_C','col_F','col_G']
include_cols = ['col_D','col_E'] # desired columns

def flag_outliers(s, exclude_cols):
    if s.name in exclude_cols:
        print(s.name)
        return '' 
    else:
        s=df[(np.abs(stats.zscore(df['col_E'])) > 3)] # not sure of this part of the code
        
        return ['background-color: yellow' if v else '' for v in indexes]

df.style.apply(lambda s: flag_outliers(s, exclude_cols), axis=1, subset=include_cols)

谢谢!

【问题讨论】:

  • stats.zscore(df['col_D'])stats.zscore(df['col_E']) 表示没有 |z| > 3 存在的异常值!
  • 还有,“两列或更多列中的 z 分数”是什么意思?您是否将这些值合并为一个样本?

标签: python pandas dataframe scipy statsmodels


【解决方案1】:

我假设以下含义来展示更广泛的用法。

  • Q1 代表计算单列
  • Q2 代表对汇集在一起​​的多个列进行计算。

如果 Q2 打算分别在多列上计算,那么您可以简单地将 Q1 解决方案循环到多列上,这应该是微不足道的,所以我将在此处省略这种情况。

  • Q1 非常简单,因为可以通过列表解析返回一个值列表。
  • Q2 有点复杂,因为 z 分数将应用于 DataFrame 子集(即必须使用 axis=None)。根据official docs,当在 DataFrame 上应用样式时,返回对象也必须是与子集具有相同索引和列的 DataFrame。这就是导致重塑和 DataFrame 构造工件的原因。

单列(Q1)

请注意,出于演示目的,z=3 已降低为 1.5。 # 想要的列 include_cols = ['col_E']

# additional control
outlier_threshold = 1.5   # 3 won't work!
ddof = 0   # degree of freedom correction. Sample = 1 and population = 0.

def flag_outliers(s: pd.Series):
    outlier_mask = np.abs(stats.zscore(s, ddof=ddof)) > outlier_threshold
    # replace boolean values with corresponding strings
    return ['background-color: yellow' if val else '' for val in outlier_mask]

df.style.apply(flag_outliers, subset=include_cols)

结果

多列合并(Q2,假设)

第二季度

include_cols = ['col_D', 'col_E']  # desired columns

outlier_threshold = 1.5
ddof = 0

def flag_outliers(s: pd.DataFrame) -> pd.DataFrame:
    outlier_mask = np.abs(stats.zscore(s.values.reshape(-1), axis=None, ddof=ddof)) > outlier_threshold
    # prepare the array of string to be returned
    arr = np.array(['background-color: yellow' if val else '' for val in outlier_mask], dtype=object).reshape(s.shape)
    # cast the array into dataframe
    return pd.DataFrame(arr, columns=s.columns, index=s.index)

df.style.apply(flag_outliers, axis=None, subset=include_cols)

结果

【讨论】:

    【解决方案2】:

    基于这个answer,只需将分数的条件传递给一个存储每列索引背景颜色的dict。

    include_cols = ['col_D', 'col_E']
    
    def color_outliers_yellow(row, include, color='yellow', z_score = 1):
        
        styles = {col: '' for col in row.index}
        
        if row.name in include:
            
            scores = stats.zscore(list(row))
            
            scores = [(f'background-color: {color}' if score > z_score else '') for score in scores]
            
            return {k:v for k, v in zip(styles.keys(), scores)}
        
        else:
            
            return styles
    
    df.style.apply(lambda x: color_outliers_yellow(x, include=include_cols), axis=0)
    

    结果:

    【讨论】:

    • 我希望有人能分解这段代码的作用/它的工作原理......对于我的情况,我想替换“异常值”而不是突出显示它们。
    • @flashliquid 你的意思是替换值吗?你能提供更多的背景吗?样式方法似乎不适合您的情况
    猜你喜欢
    • 2015-09-13
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 2022-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多