从数组中移除异常值的技术
Outlier removal techniques from an array
我知道网上有大量资源可用于移除异常值,但我还没有设法获得我真正想要的东西,所以在这里发布,我有一个 4
列的数组(或 DF)。现在我想根据列的离群值从 DF 中删除行。以下是我尝试过的,但并不完美。
def outliers2(data2, m = 4.5):
c=[]
data = data2[:,1] # Choosing the column
d = np.abs(data - np.median(data)) # deviation comoutation
mdev = np.median(d) # mean deviation
for i in range(len(data)):
if (abs(data[i] - mdev) < m * np.std(data)):
c.append(data2[i])
return c
x = pd.DataFrame(outliers2(np.array(b)))
column = ['t','orig_w','filt_w','smt_w']
x.columns = column
#Plot
plt.rcParams['figure.figsize'] = [10,8]
plt.plot(b.t,b.orig_w,'o',label='Original',alpha=0.8) # Original
plt.plot(x.t,x.orig_w,'.',c='r',label='Outlier removed',alpha=0.8) # After outlier removal
plt.legend()
该图说明了结果的外观,在蓝色原始点上进行异常值处理后的红色点。我真的很想摆脱 x~0 标记周围的那些垂直点组。怎么办?
此处提供了数据文件的link:Full data
绿色圆圈通常显示我想摆脱的点
由于您的数据看起来呈正弦曲线,因此使用滑动 window 执行异常值移除技术可能是有意义的。您可以计算您正在测试的点的直接邻域中的中值和标准差,并通过检查您的点是否在与中值的标准差的指定数量内来检查它是否是异常值。此方法以 Hampel filter
的名称存在(更多详细信息 here and here)。下面是一种实现它的方法,window 大小等于每边 50 个样本,阈值基于 1.25 std:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df_orig=pd.read_csv('trial_data.csv')
def hampel_filter(df_orig, m = 1.25,win=50):
c=[]
k = 1.4826
for i in range(len(df_orig)):
med=np.median(df_orig['orig_w'][np.amax([0,i-win]):np.amin([len(df_orig['orig_w']),i+win])])
mad=np.std(np.abs(df_orig['orig_w'][np.amax([0,i-win]):np.amin([len(df_orig['orig_w']),i+win])]-med))
sigma=k*mad
if np.abs(med-df_orig['orig_w'][i])<m*sigma:
c.append(df_orig.loc[i])
return c
x = pd.DataFrame(hampel_filter(df_orig))
column = ['t','orig_w','filt_w','smt_w']
x.columns = column
#Plot
plt.rcParams['figure.figsize'] = [10,8]
plt.plot(df['t'],df['orig_w'],'o',label='Original',alpha=0.8) # Original
plt.plot(x.t,x.orig_w,'.',c='r',label='Outlier removed',alpha=0.8) # After outlier removal
plt.legend()
并且输出给出:
然后您可以微调 win
和 m
以获得适合您的结果。
您可以使用 scipy's median_filter:
import pandas as pd
from matplotlib import pyplot as plt
from scipy.ndimage import median_filter
b = pd.read_csv("test.csv")
x = b.copy()
x.orig_w = median_filter(b.orig_w, size=15)
#Plot
plt.rcParams['figure.figsize'] = [10,8]
#Original
plt.plot(b.t,b.orig_w,'o',label='Original',alpha=0.8)
# After outlier removal
plt.plot(x.t,x.orig_w,'.',c='r',label='Outlier removed',alpha=0.8)
plt.legend()
plt.show()
示例输出:
我知道网上有大量资源可用于移除异常值,但我还没有设法获得我真正想要的东西,所以在这里发布,我有一个 4
列的数组(或 DF)。现在我想根据列的离群值从 DF 中删除行。以下是我尝试过的,但并不完美。
def outliers2(data2, m = 4.5):
c=[]
data = data2[:,1] # Choosing the column
d = np.abs(data - np.median(data)) # deviation comoutation
mdev = np.median(d) # mean deviation
for i in range(len(data)):
if (abs(data[i] - mdev) < m * np.std(data)):
c.append(data2[i])
return c
x = pd.DataFrame(outliers2(np.array(b)))
column = ['t','orig_w','filt_w','smt_w']
x.columns = column
#Plot
plt.rcParams['figure.figsize'] = [10,8]
plt.plot(b.t,b.orig_w,'o',label='Original',alpha=0.8) # Original
plt.plot(x.t,x.orig_w,'.',c='r',label='Outlier removed',alpha=0.8) # After outlier removal
plt.legend()
该图说明了结果的外观,在蓝色原始点上进行异常值处理后的红色点。我真的很想摆脱 x~0 标记周围的那些垂直点组。怎么办?
此处提供了数据文件的link:Full data
由于您的数据看起来呈正弦曲线,因此使用滑动 window 执行异常值移除技术可能是有意义的。您可以计算您正在测试的点的直接邻域中的中值和标准差,并通过检查您的点是否在与中值的标准差的指定数量内来检查它是否是异常值。此方法以 Hampel filter
的名称存在(更多详细信息 here and here)。下面是一种实现它的方法,window 大小等于每边 50 个样本,阈值基于 1.25 std:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df_orig=pd.read_csv('trial_data.csv')
def hampel_filter(df_orig, m = 1.25,win=50):
c=[]
k = 1.4826
for i in range(len(df_orig)):
med=np.median(df_orig['orig_w'][np.amax([0,i-win]):np.amin([len(df_orig['orig_w']),i+win])])
mad=np.std(np.abs(df_orig['orig_w'][np.amax([0,i-win]):np.amin([len(df_orig['orig_w']),i+win])]-med))
sigma=k*mad
if np.abs(med-df_orig['orig_w'][i])<m*sigma:
c.append(df_orig.loc[i])
return c
x = pd.DataFrame(hampel_filter(df_orig))
column = ['t','orig_w','filt_w','smt_w']
x.columns = column
#Plot
plt.rcParams['figure.figsize'] = [10,8]
plt.plot(df['t'],df['orig_w'],'o',label='Original',alpha=0.8) # Original
plt.plot(x.t,x.orig_w,'.',c='r',label='Outlier removed',alpha=0.8) # After outlier removal
plt.legend()
并且输出给出:
然后您可以微调 win
和 m
以获得适合您的结果。
您可以使用 scipy's median_filter:
import pandas as pd
from matplotlib import pyplot as plt
from scipy.ndimage import median_filter
b = pd.read_csv("test.csv")
x = b.copy()
x.orig_w = median_filter(b.orig_w, size=15)
#Plot
plt.rcParams['figure.figsize'] = [10,8]
#Original
plt.plot(b.t,b.orig_w,'o',label='Original',alpha=0.8)
# After outlier removal
plt.plot(x.t,x.orig_w,'.',c='r',label='Outlier removed',alpha=0.8)
plt.legend()
plt.show()
示例输出: