Pandas - 使用groupby均值替换异常值

3

我有一个Pandas数据框,我想把它分成几组,计算均值和标准差,然后用组的均值替换所有异常值。如果异常值与组均值相差超过3个标准差,则定义为异常值。

df = pandas.DataFrame({'a': ['A','A','A','B','B','B','B'], 'b': [1.1,1.2,1.1,3.3,3.4,3.3,100.0]})

我认为以下内容会有效果:

我认为以下内容会有效果:

df.groupby('a')['b'].transform(lambda x: x[i] if np.abs(x[i]-x.mean())<=(3*x.std()) else x.mean() for i in range(0,len(x)))

但是遇到了以下错误:

NameError: name 'x' is not defined

我还尝试过单独定义一个转换函数:

def trans_func(x):
    mean = x.mean()
    std = x.std()
    length = len(x)
    for i in range(0,length):
        if abs(x[i]-mean)<=(3*std):
            return x
        else:
            return mean

然后像这样调用它:

df.groupby('a')['b'].transform(lambda x: trans_func(x))

但是我得到了一个不同的错误:

关键错误:0

最后,我不得不创建一个单独的列:

df['c'] = [df.groupby('a')['b'].transform(mean) if df.groupby('a')['b'].transform(lambda x: (x - x.mean()) / x.std()) > 3 else df['b']] 

但这也没有起作用:

ValueError:一个Series的真值是不明确的。使用a.empty,a.bool(),a.item(),a.any()或a.all()。

非常感谢您的任何建议。

3个回答

8

试试这个:

def replace(group):
    mean, std = group.mean(), group.std()
    outliers = (group - mean).abs() > 3*std
    group[outliers] = mean        # or "group[~outliers].mean()"
    return group

df.groupby('a').transform(replace)

注意:如果您想在最后一组中消除100,您可以将3*std替换为1*std。该组的标准偏差为48.33,因此它将包含在结果中。

1
但是这个均值不会受到异常值的影响吗? - jayarjo

6

首先应该移除异常值,然后计算组均值进行替换。如果使用含有异常值的均值进行替换,则均值会受到异常值的影响。


0

希望这会有所帮助:

步骤1,去除离群值(参考自pandas group by remove outliers):

def is_outlier(s):
    lower_limit = s.mean() - (s.std() * 3)
    upper_limit = s.mean() + (s.std() * 3)
    return ~s.between(lower_limit, upper_limit)

df = df[~df.groupby('a')['count'].apply(is_outlier)]

第二步,替换异常值(参考自elyase):

def replace(group):
    mean, std = group.mean(), group.std()
    outliers = (group - mean).abs() > 3*std
    group[outliers] = mean        # or "group[~outliers].mean()"
    return group

df.groupby('a').transform(replace)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接