0
votes

Correction des valeurs aberrantes avec une fonction définie par l'utilisateur

J'essaie d'écrire une fonction qui corrigera les valeurs aberrantes dans l'ensemble de données. c'est-à-dire que si la valeur aberrante est au-dessus de la limite supérieure, la valeur sera remplacée par la limite supérieure et si la valeur est inférieure à la limite inférieure, elle sera remplacée par la limite inférieure. La fonction que j'ai créée est répertoriée ci-dessous.

def fix_outliers(df):
    anomalies = []
    df_std = np.std(df)
    df_mean = np.mean(df)
    anomaly_cut_off = df_std * 3
    lower_limit  = df_mean - anomaly_cut_off 
    upper_limit = df_mean + anomaly_cut_off
    df=np.where(df > upper_limit, upper_limit, df)
    df=np.where(df < lower_limit, lower_limit, df)

Les changements qui se produisent à l'intérieur de la fonction ne sont pas modifiés dans mon ensemble de données. Je suis nouveau en python et en particulier avec les fonctions. Toute aide serait appréciée. Merci d'avance.

Cordialement, Vin


1 commentaires

L'entrée (df) est-elle une trame de données pandas? ou regardez-vous simplement des tableaux numpy?


4 Réponses :


0
votes

Si je lis correctement la question, l'entrée est un dataframe pandas. Si tel est le cas, voici une solution:

NUM_STD = 3 # not strictly needed. Defines what's an outlier. 

def outliers(df):
    df[df > (df.std() * NUM_STD + df.mean())] = list(df.std() * NUM_STD + df.mean())
    df[df < (df.mean() - df.std() * NUM_STD)] = list(df.mean() - df.std() * NUM_STD)
    return df

# for demo purposes - create a dataframe and run outliers. 
normal_dist = lambda : np.random.normal(loc = 100, scale = 50, size = 100)
df = pd.DataFrame({"a" : normal_dist(), "b": normal_dist()})
outliers(df)


0 commentaires

0
votes

Les modifications ne sont pas visibles en dehors de votre fonction car np.where crée un nouveau tableau. Les variables en Python se comportent comme des étiquettes pointant vers des objets (en quelque sorte similaires aux pointeurs C). Par conséquent, l'opération:

def fix_outliers(df):
    df_std = np.std(df)
    df_mean = np.mean(df)
    anomaly_cut_off = df_std * 3
    lower_limit  = df_mean - anomaly_cut_off 
    upper_limit = df_mean + anomaly_cut_off
    np.clip(df, lower_limit, upper_limit, out=df)

mettra à jour le libellé df mais elle ne changera pas l'objet que df pointait à.

Une mise à jour appropriée ressemblerait à ceci:

np.clip(df, lower_limit, upper_limit, out=df)

BTW. Il existe une fonction numpy dédiée à cette tâche. Il s'agit de np.clip . L'opération peut être écrasée en:

df[df > upper_limit] = upper_limit
df[df < lower_limit] = lower_limit

La fonction finale serait:

df = <something>


0 commentaires

0
votes

Voici une proposition:

def fix_outliers(df):
    
    df_mean=np.nanmean(df)
    df_std=np.nanstd(df)

    upper_limit=df_mean+3*df_std
    lower_limit=df_mean-3*df_std

    df[df>upper_limit]=upper_limit
    df[df<lower_limit]=lower_limit
   

fix_outliers(df)

Je pense qu'il vaut mieux créer une copie du dataframe puis le modifier au lieu de perdre les données brutes. Si vous ne souhaitez toujours modifier que df:

def fix_outliers(df):

    df_fx=df.copy()
    df_fx_mean=np.nanmean(df_fx)
    df_fx_std=np.nanstd(df_fx)

    upper_limit=df_fx_mean+3*df_fx_std
    lower_limit=df_fx_mean-3*df_fx_std

    df_fx[df_fx>upper_limit]=upper_limit
    df_fx[df_fx<lower_limit]=lower_limit

    return df_fx

df_fixed=fix_outliers(df)


1 commentaires

vous calculez moyenne et std deux fois



0
votes

En utilisant le code que vous avez fourni:

def fix_outliers(df):
    df_std = np.std(df)
    df_mean = np.mean(df)
    anomaly_cut_off = df_std * 3
    lower_limit  = df_mean - anomaly_cut_off 
    upper_limit = df_mean + anomaly_cut_off

    for col in df.columns:
        for i in range(df.shape[0]):
            if df[col][i] > upper_limit[col]:
                df[col][i] = upper_limit[col]
            elif df[col][i] < lower_limit[col]:
                df[col][i] = lower_limit[col]

    return df


0 commentaires