首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >大型熊猫DataFrame中按组删除异常值的更快方法

大型熊猫DataFrame中按组删除异常值的更快方法
EN

Stack Overflow用户
提问于 2014-12-11 21:37:39
回答 5查看 34K关注 0票数 15

我有一个相对较大的DataFrame对象(大约一百万行,几百列),并且我想逐组裁剪每列中的离群值。我的意思是“逐组剪裁每列的异常值”-计算组中每列的5%和95%分位数,并剪裁该分位数范围之外的值。

下面是我目前正在使用的设置:

代码语言:javascript
代码运行次数:0
运行
复制
def winsorize_series(s):
    q = s.quantile([0.05, 0.95])
    if isinstance(q, pd.Series) and len(q) == 2:
        s[s < q.iloc[0]] = q.iloc[0]
        s[s > q.iloc[1]] = q.iloc[1]
    return s

def winsorize_df(df):
    return df.apply(winsorize_series, axis=0)

然后,使用名为features并由DATE编制索引的DataFrame,我可以执行以下操作

代码语言:javascript
代码运行次数:0
运行
复制
grouped = features.groupby(level='DATE')
result = grouped.apply(winsorize_df)

这是可行的,除非它非常慢,这可能是由于嵌套的apply调用:每组一个,然后每组中的每列一个。我试图通过一次计算所有列的分位数来消除第二个apply,但在尝试通过不同的值设置每列的阈值时遇到了问题。有没有更快的方法来完成这个过程?

EN

回答 5

Stack Overflow用户

发布于 2014-12-11 23:13:04

有一个你可以考虑使用的winsorize function in scipy.stats.mstats。但是请注意,它返回的值与winsorize_series略有不同

代码语言:javascript
代码运行次数:0
运行
复制
In [126]: winsorize_series(pd.Series(range(20), dtype='float'))[0]
Out[126]: 0.95000000000000007

In [127]: mstats.winsorize(pd.Series(range(20), dtype='float'), limits=[0.05, 0.05])[0]
Out[127]: 1.0

使用mstats.winsorize而不是winsorize_series可能(取决于N,M,P)大约快1.5倍:

代码语言:javascript
代码运行次数:0
运行
复制
import numpy as np
import pandas as pd
from scipy.stats import mstats

def using_mstats_df(df):
    return df.apply(using_mstats, axis=0)

def using_mstats(s):
    return mstats.winsorize(s, limits=[0.05, 0.05])

N, M, P = 10**5, 10, 10**2
dates = pd.date_range('2001-01-01', periods=N//P, freq='D').repeat(P)
df = pd.DataFrame(np.random.random((N, M))
                  , index=dates)
df.index.names = ['DATE']
grouped = df.groupby(level='DATE')

代码语言:javascript
代码运行次数:0
运行
复制
In [122]: %timeit result = grouped.apply(winsorize_df)
1 loops, best of 3: 17.8 s per loop

In [123]: %timeit mstats_result = grouped.apply(using_mstats_df)
1 loops, best of 3: 11.2 s per loop
票数 9
EN

Stack Overflow用户

发布于 2019-04-16 18:55:08

这是一个不使用scipy.stats.mstats的解决方案:

代码语言:javascript
代码运行次数:0
运行
复制
def clip_series(s, lower, upper):
   clipped = s.clip(lower=s.quantile(lower), upper=s.quantile(upper), axis=1)
   return clipped

# Manage list of features to be winsorized
feature_list = list(features.columns)

for f in feature_list:
   features[f] = clip_series(features[f], 0.05, 0.95)
票数 7
EN

Stack Overflow用户

发布于 2017-09-07 01:05:40

我找到了一种相当简单的方法来实现这一点,在pandas中使用transform方法。

代码语言:javascript
代码运行次数:0
运行
复制
from scipy.stats import mstats

def winsorize_series(group):
    return mstats.winsorize(group, limits=[lower_lim,upper_lim])

grouped = features.groupby(level='DATE')
result = grouped.transform(winsorize_series)
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27424178

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档