Técnicas de eliminación de valores atípicos de una matriz

Sé que hay una tonelada de recursos en línea para la eliminación de valores atípicos, pero aún no he logrado obtener exactamente lo que quiero, así que publicando aquí, tengo una matriz (o DF) de 4columnas. Ahora quiero eliminar las filas del DF en función de los valores atípicos de una columna. Lo siguiente es lo que he probado, pero no son perfectos.

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()

el gráfico ilustra cómo se ven los resultados, puntos rojos después del tratamiento de valores atípicos sobre los puntos originales azules. Realmente me gustaría deshacerme de ese grupo vertical de puntos alrededor de la marca x~0. Qué hacer ?

Aquí se proporciona un enlace al archivo de datos: Datos completos ingrese la descripción de la imagen aquí Los círculos verdes muestran típicamente los puntos de los que me gustaría deshacerme ingrese la descripción de la imagen aquí

Answer

Podrías usar el filtro median_filter de scipy :

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()

Salida de muestra: ingrese la descripción de la imagen aquí

Dado que sus datos parecen sinusoidales, probablemente tenga sentido realizar su técnica de eliminación de valores atípicos mediante el uso de una ventana deslizante. Puede calcular la mediana y la desviación estándar en la vecindad directa de los puntos que está probando y verificar si es un valor atípico verificando si su punto está dentro de un número específico de la desviación estándar de su mediana. Este método existe bajo el nombre de Hampel filter(más detalles aquí y aquí ). A continuación se muestra una forma de implementarlo con un tamaño de ventana igual a 50 muestras en cada lado y un umbral basado en 1,25 estándar:

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()

Y la salida da:

ingrese la descripción de la imagen aquí

Luego puede ajustar winy mobtener un resultado que funcione para usted.