我有一个很少列的熊猫数据帧。

现在我知道某些行是基于某个列值的异常值。

例如

列“Vol”的所有值都在12xx左右,其中一个值是4000(离群值)。

现在我想排除那些Vol列像这样的行。

所以,本质上,我需要在数据帧上放一个过滤器,这样我们就可以选择所有的行,其中某一列的值距离平均值在3个标准差之内。

实现这一点的优雅方式是什么?


当前回答

这个答案类似于@tanemaki提供的答案,但使用了lambda表达式而不是scipy stats。

df = pd.DataFrame(np.random.randn(100, 3), columns=list('ABC'))

standard_deviations = 3
df[df.apply(lambda x: np.abs(x - x.mean()) / x.std() < standard_deviations)
   .all(axis=1)]

要过滤只有一个列的数据帧(例如:B)在三个标准差之内:

df[((df['B'] - df['B'].mean()) / df['B'].std()).abs() < standard_deviations]

关于如何在滚动的基础上应用这个z-score:滚动z-score应用于pandas数据框架

其他回答

另一种选择是转换数据,以减轻异常值的影响。你可以通过winsorize你的数据来做到这一点。

import pandas as pd
from scipy.stats import mstats
%matplotlib inline

test_data = pd.Series(range(30))
test_data.plot()

# Truncate values to the 5th and 95th percentiles
transformed_test_data = pd.Series(mstats.winsorize(test_data, limits=[0.05, 0.05])) 
transformed_test_data.plot()

对于数据框架中的每个系列,您可以使用between和分位数来删除异常值。

x = pd.Series(np.random.normal(size=200)) # with outliers
x = x[x.between(x.quantile(.25), x.quantile(.75))] # without outliers

对于你的每一个数据帧列,你可以得到分位数:

q = df["col"].quantile(0.99)

然后用:

df[df["col"] < q]

如果需要移除上下异常值,将condition与and语句结合:

q_low = df["col"].quantile(0.01)
q_hi  = df["col"].quantile(0.99)

df_filtered = df[(df["col"] < q_hi) & (df["col"] > q_low)]

我认为删除和删除异常值在统计上是错误的。 它使数据不同于原始数据。 也使得数据的形状不均匀,因此最好的方法是通过对数据进行对数变换来减少或避免异常值的影响。 这招对我很管用:

np.log(data.iloc[:, :])

把98和2百分位作为离群值的极限

upper_limit = np.percentile(X_train.logerror.values, 98) 
lower_limit = np.percentile(X_train.logerror.values, 2) # Filter the outliers from the dataframe
data[‘target’].loc[X_train[‘target’]>upper_limit] = upper_limit data[‘target’].loc[X_train[‘target’]<lower_limit] = lower_limit