Python 按组执行列操作

问题描述 投票:0回答:1

我正在尝试在组级别上删除异常值列(Property1、Property2 等),需要您的帮助。

这是我的示例数据框,包含 2 个组和 4 个属性。

团体 财产1 房产2 房产3 房产4
A 10 15 1.5 5
B 11 14 1.7 4.8
B 11 14.1 1.8 5
A 9 13 3.5 21
B 8 40 1.2 3

以下是我只有一组时使用的代码。我正在使用 GESD 方法来删除异常值并使用 PyAstronomy 库的 GeneralizedESD 函数。

for column in dataset.iloc[:, 1:]:        #iterate through each column that needs outlier removed
    column1 = dataset[column].dropna()      #drop na
    column1.reset_index(drop=True, inplace=True)  # reset index to account for removed NAs
    length = len(column1)                        #calculate number of rows
    max_outlier = int(length*0.25)               #set max number of outliers
    if length>2:
        r = pyasl.generalizedESD(column1, max_outlier, 0.05, fullOutput=False)   
        i = r[1]                                                   # array of indices of the outliers  
        a = (column1.loc[i])                                        # array of outlier values
        for x in a:
            dataset.loc[dataset[column]==x, column] = np.nan   #replace outlier with nan

我想在组级别上执行此操作,其中该操作为两个组中的每一个运行 2 次,结果是用 NAN 替换异常值的单个 df。 谁能建议一种方法来做到这一点? 我尝试将上面的代码包装在一个函数中并使用 groupby 和 apply。但我没有得到想要的结果。

python pandas outliers
1个回答
0
投票

首先,您的示例很容易失败,因为如果每组的列数太少,您最终会得到

max_outlier = 0
,这是
generalizedESD
不喜欢的。因此,让我们从一个更好的示例数据集开始:

import numpy as np                                                                                      
import pandas as pd                                                                                     
                                                                                                        
from PyAstronomy import pyasl                                                                           
                                                                                                        
# Create synthetic data of three groups with random outliers (values ~20)                                               
n = 50                                                                                                  
dataset = pd.DataFrame({                                                                                
    "Group":                                                                                            
    np.random.choice(["A", "B", "C"], size=n),                                                          
    "P1":                                                                                               
    np.random.rand(n) + np.random.choice([0., 20.], p=[0.9, 0.1], size=n),                              
    "P2":                                                                                               
    np.random.rand(n) + np.random.choice([0., 20.], p=[0.9, 0.1], size=n),                              
    "P3":                                                                                               
    np.random.rand(n) + np.random.choice([0., 20.], p=[0.9, 0.1], size=n),                              
    "P4":                                                                                               
    np.random.rand(n) + np.random.choice([0., 20.], p=[0.9, 0.1], size=n)                               
})                                                                                                      
                                                                                                        
dataset = dataset.set_index("Group")

接下来,您可以像这样逐列替换整个数据集上的值:

def replace_outliers_columnwise(col):                                                                   
    max_out = len(col) // 4                                                                             
    _, idxs = pyasl.generalizedESD(col, max_out)                                                        
    col.iloc[idxs] = np.nan                                                                             
    return col                                                                                          
                                                                                                        
dataset = dataset.apply(replace_outliers_columnwise, axis=0)                                            
print(dataset)                                                                  

这将打印您开始使用的完全相同的数据集,但用 NaN 替换异常值。

请注意,上面的

generalizedESD
不只是返回一些东西,而是返回一个元组,相关的就是我所说的
idxs
,一个包含被检测为异常值的元素的索引的数组。

相反,如果出于某种原因您想按组执行此操作,那么您可以先分组然后应用到每个组,就像您提到的:

def replace_outliers_groupwise(group):                                                                  
    return group.apply(replace_outliers_columnwise)                                                     
                                                                                                        
                                                                                                        
dataset = dataset.groupby("Group").apply(replace_outliers_groupwise)                                    
print(dataset)

它将打印相同的数据帧,但现在带有稍微不同的索引,表示数据帧被分割成的不同组。

© www.soinside.com 2019 - 2024. All rights reserved.