我有一个很少列的熊猫数据帧。
现在我知道某些行是基于某个列值的异常值。
例如
列“Vol”的所有值都在12xx左右,其中一个值是4000(离群值)。
现在我想排除那些Vol列像这样的行。
所以,本质上,我需要在数据帧上放一个过滤器,这样我们就可以选择所有的行,其中某一列的值距离平均值在3个标准差之内。
实现这一点的优雅方式是什么?
我有一个很少列的熊猫数据帧。
现在我知道某些行是基于某个列值的异常值。
例如
列“Vol”的所有值都在12xx左右,其中一个值是4000(离群值)。
现在我想排除那些Vol列像这样的行。
所以,本质上,我需要在数据帧上放一个过滤器,这样我们就可以选择所有的行,其中某一列的值距离平均值在3个标准差之内。
实现这一点的优雅方式是什么?
当前回答
像在numpy.array中那样使用布尔索引
df = pd.DataFrame({'Data':np.random.normal(size=200)})
# example dataset of normally distributed data.
df[np.abs(df.Data-df.Data.mean()) <= (3*df.Data.std())]
# keep only the ones that are within +3 to -3 standard deviations in the column 'Data'.
df[~(np.abs(df.Data-df.Data.mean()) > (3*df.Data.std()))]
# or if you prefer the other way around
对于一个系列,它是类似的:
S = pd.Series(np.random.normal(size=200))
S[~((S-S.mean()).abs() > 3*S.std())]
其他回答
你可以使用布尔掩码:
import pandas as pd
def remove_outliers(df, q=0.05):
upper = df.quantile(1-q)
lower = df.quantile(q)
mask = (df < upper) & (df > lower)
return mask
t = pd.DataFrame({'train': [1,1,2,3,4,5,6,7,8,9,9],
'y': [1,0,0,1,1,0,0,1,1,1,0]})
mask = remove_outliers(t['train'], 0.1)
print(t[mask])
输出:
train y
2 2 0
3 3 1
4 4 1
5 5 0
6 6 0
7 7 1
8 8 1
这个答案类似于@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数据框架
我喜欢夹而不喜欢掉。以下将夹在第2和98分频。
df_list = list(df)
minPercentile = 0.02
maxPercentile = 0.98
for _ in range(numCols):
df[df_list[_]] = df[df_list[_]].clip((df[df_list[_]].quantile(minPercentile)),(df[df_list[_]].quantile(maxPercentile)))
把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
另一种选择是转换数据,以减轻异常值的影响。你可以通过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()