我有一个相对较大的DataFrame对象(大约一百万行,成百上千列),我想按组剪裁每列中的异常值。我的意思是,通过“逐组剪裁每列的异常值”,计算一个组中每列的5%和95%分位数,并剪裁该分位数范围之外的值。
以下是我当前使用的设置:
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
索引的数据帧,我可以
grouped = features.groupby(level='DATE')
result = grouped.apply(winsorize_df)
这是可行的,只是速度很慢,可能是因为嵌套的apply
调用:每个组一个,然后每个组中的每个列一个。我试图通过一次计算所有列的分位数来去掉第二个apply
,但却被困在试图用不同的值对每个列设置阈值。有没有更快的方法来完成这个过程?
有一个winsorize function in scipy.stats.mstats可以考虑使用。但是,请注意,它返回的值与
winsorize_series
略有不同:用
mstats.winsorize
代替winsorize_series
可能(取决于N,M,p)快1.5倍:解决这个问题的好方法是矢量化。为此,我喜欢使用
np.where
。为了进行比较,我将
scipy
中的函数包装在一个函数中:但正如您所看到的,尽管我的函数非常快,但它离Scipy实现还很远:
如果您有兴趣阅读更多关于加速pandas代码的内容,我建议您使用Optimization Pandas for speed和From Python to Numpy。
我找到了一个非常简单的方法来实现这一点,在pandas中使用了transform方法。
相关问题 更多 >
编程相关推荐