Python 检测并排除数据帧中的异常值
我有一个熊猫数据框,几乎没有列 现在我知道某些行是基于特定列值的异常值 比如说 “Vol”列的所有值都在Python 检测并排除数据帧中的异常值,python,pandas,filtering,dataframe,outliers,Python,Pandas,Filtering,Dataframe,Outliers,我有一个熊猫数据框,几乎没有列 现在我知道某些行是基于特定列值的异常值 比如说 “Vol”列的所有值都在12xx附近,其中一个值为4000(异常值) 现在,我想排除那些像这样有Vol列的行 所以,本质上我需要在数据框上放置一个过滤器,这样我们就可以选择所有行,其中某一列的值在,比如说,平均值的3个标准偏差之内 实现这一点的优雅方法是什么?像在numpy.array中那样使用boolean索引 df = pd.DataFrame({'Data':np.random.normal(size=200)
12xx
附近,其中一个值为4000
(异常值)
现在,我想排除那些像这样有Vol
列的行
所以,本质上我需要在数据框上放置一个过滤器,这样我们就可以选择所有行,其中某一列的值在,比如说,平均值的3个标准偏差之内
实现这一点的优雅方法是什么?像在
numpy.array中那样使用boolean
索引
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
如果您的数据帧中有多个列,并且希望删除至少一列中包含异常值的所有行,则以下表达式可以一次性完成此操作。
df = pd.DataFrame(np.random.randn(100, 3))
from scipy import stats
df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]
这个答案与@tanemaki提供的答案类似,但使用了lambda
表达式,而不是scipy stats
df = pd.DataFrame(np.random.randn(100, 3), columns=list('ABC'))
df[df.apply(lambda x: np.abs(x - x.mean()) / x.std() < 3).all(axis=1)]
df=pd.DataFrame(np.random.randn(100,3),columns=list('ABC'))
df[df.apply(λx:np.abs(x-x.mean())/x.std()<3)。全部(轴=1)]
要过滤只有一列(例如“B”)在三个标准偏差范围内的数据帧:
df[((df.B - df.B.mean()) / df.B.std()).abs() < 3]
df[((df.B-df.B.mean())/df.B.std()).abs()<3]
请参见此处,了解如何在滚动基础上应用此z分数:scipy.stats
有方法trim1()
和trimleath()
根据排名和引入的删除值百分比,在一行中删除异常值。对于每个数据框列,您可以使用以下方法获得分位数:
q = df["col"].quantile(0.99)
然后使用以下内容进行过滤:
df[df["col"] < q]
df[df[“col”]
如果需要删除下限和上限异常值,请将条件与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)]
q_low=df[“col”]。分位数(0.01)
q_hi=df[“col”]。分位数(0.99)
df_filtered=df[(df[“col”]q_low)]
另一种选择是转换数据,以减轻异常值的影响。您可以通过winsorizing数据来实现这一点
import pandas as pd
from scipy.stats import mstats
%matplotlib inline
test_data = pd.Series(range(30))
test_data.plot()
#------------------------------------------------------------------------------
#接受数据帧,删除异常值,在新的数据帧中返回清理后的数据
#看http://www.itl.nist.gov/div898/handbook/prc/section1/prc16.htm
#------------------------------------------------------------------------------
def删除异常值(df_in,列名称):
q1=df_in[col_name]。分位数(0.25)
q3=df_in[col_name]。分位数(0.75)
iqr=q3-q1#四分位数范围
围栏低=q1-1.5*iqr
围栏高度=q3+1.5*iqr
df_out=df_in.loc[(df_in[col_name]>围栏低)和(df_in[col_name]<围栏高)]
返回dfu
如果您喜欢方法链接,您可以获得所有数字列的布尔条件,如下所示:
df.sub(df.mean()).div(df.std()).abs().lt(3)
每列的每个值将根据其与平均值之间的标准偏差是否小于三个标准偏差,转换为真/假。下面是一个完整的数据示例和两组:
进口:
from StringIO import StringIO
import pandas as pd
#pandas config
pd.set_option('display.max_rows', 20)
数据示例包含两组:G1:第1组。G2:第2组:
TESTDATA = StringIO("""G1;G2;Value
1;A;1.6
1;A;5.1
1;A;7.1
1;A;8.1
1;B;21.1
1;B;22.1
1;B;24.1
1;B;30.6
2;A;40.6
2;A;51.1
2;A;52.1
2;A;60.6
2;B;80.1
2;B;70.6
2;B;90.6
2;B;85.1
""")
将文本数据读取到数据框:
df = pd.read_csv(TESTDATA, sep=";")
使用标准偏差定义异常值
stds = 1.0
outliers = df[['G1', 'G2', 'Value']].groupby(['G1','G2']).transform(
lambda group: (group - group.mean()).abs().div(group.std())) > stds
定义过滤数据值和异常值:
dfv = df[outliers.Value == False]
dfo = df[outliers.Value == True]
打印结果:
print '\n'*5, 'All values with decimal 1 are non-outliers. In the other hand, all values with 6 in the decimal are.'
print '\nDef DATA:\n%s\n\nFiltred Values with %s stds:\n%s\n\nOutliers:\n%s' %(df, stds, dfv, dfo)
删除异常值的函数
def drop_outliers(df, field_name):
distance = 1.5 * (np.percentile(df[field_name], 75) - np.percentile(df[field_name], 25))
df.drop(df[df[field_name] > distance + np.percentile(df[field_name], 75)].index, inplace=True)
df.drop(df[df[field_name] < np.percentile(df[field_name], 25) - distance].index, inplace=True)
def drop_异常值(df,字段名称):
距离=1.5*(np.百分位数(df[字段名称],75)-np.百分位数(df[字段名称],25))
df.drop(df[df[field\u name]>距离+np.百分位数(df[field\u name],75)]。索引,原地=真)
df.drop(df[df[field\u name]
从统计学上讲,我认为删除和删除异常值是错误的。
它使数据与原始数据不同。
也会使数据形状不均匀,因此最好的方法是通过对数据进行对数变换来减少或避免异常值的影响。
这对我很有用:
np.log(data.iloc[:, :])
我宁愿剪掉也不愿摔下来。以下内容将卡在第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)))
由于我正处于数据科学旅程的早期阶段,我将使用下面的代码处理异常值
#Outlier Treatment
def outlier_detect(df):
for i in df.describe().columns:
Q1=df.describe().at['25%',i]
Q3=df.describe().at['75%',i]
IQR=Q3 - Q1
LTV=Q1 - 1.5 * IQR
UTV=Q3 + 1.5 * IQR
x=np.array(df[i])
p=[]
for j in x:
if j < LTV or j>UTV:
p.append(df[i].median())
else:
p.append(j)
df[i]=p
return df
#异常值处理
def异常值检测(df):
对于df.descripe()列中的i:
Q1=df.descripe().在['25%',i]
Q3=df.descripe().在['75%',i]
IQR=Q3-Q1
LTV=Q1-1.5*IQR
UTV=Q3+1.5*IQR
x=np.数组(df[i])
p=[]
对于x中的j:
如果jUTV:
p、 追加(df[i].median())
其他:
p、 附加(j)
df[i]=p
返回df
对于数据帧中的每个序列,可以使用和分位数之间的来删除异常值
x = pd.Series(np.random.normal(size=200)) # with outliers
x = x[x.between(x.quantile(.25), x.quantile(.75))] # without outliers
将第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
上限=np.百分位(X_train.logerror.values,98)
下限=np.百分位数(X_train.logerror.values,2)#从数据帧中过滤异常值
数据['target'].loc[X_列['target']>上限]=上限数据['target'].loc[X_列['target']您可以使用布尔掩码:
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])
因为我还没有看到一个关于数字和非数字属性的答案,这里是一个补充答案
您可能只想删除数值属性上的异常值(分类变量很难是异常值)
功能定义
我扩展了@tanemaki的建议,即在同时存在非数字属性时处理数据:
from scipy import stats
def drop_numerical_outliers(df, z_thresh=3):
# Constrains will contain `True` or `False` depending on if it is a value below the threshold.
constrains = df.select_dtypes(include=[np.number]) \
.apply(lambda x: np.abs(stats.zscore(x)) < z_thresh, reduce=False) \
.all(axis=1)
# Drop (inplace) values set to be rejected
df.drop(df.index[~constrains], inplace=True)
示例
drop_numerical_outliers(df)
想象一个数据集df
,其中包含一些关于房屋的值:胡同、土地等高线、销售价格等,例如:
首先,您希望在散点图(z-score Thresh=3)上可视化数据:
他们是一个DataFrame.abs()
FYI,也是DataFrame.clip()
在clip()
的情况下,Jeff,轮廓没有被删除:df.一些数据.clip(-3s
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
from scipy import stats
def drop_numerical_outliers(df, z_thresh=3):
# Constrains will contain `True` or `False` depending on if it is a value below the threshold.
constrains = df.select_dtypes(include=[np.number]) \
.apply(lambda x: np.abs(stats.zscore(x)) < z_thresh, reduce=False) \
.all(axis=1)
# Drop (inplace) values set to be rejected
df.drop(df.index[~constrains], inplace=True)
drop_numerical_outliers(df)
# Plot data before dropping those greater than z-score 3.
# The scatterAreaVsPrice function's definition has been removed for readability's sake.
scatterAreaVsPrice(df)
# Drop the outliers on every attributes
drop_numerical_outliers(train_df)
# Plot the result. All outliers were dropped. Note that the red points are not
# the same outliers from the first plot, but the new computed outliers based on the new data-frame.
scatterAreaVsPrice(train_df)