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
4 Réponses :
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)
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>
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)
vous calculez moyenne et std deux fois
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
L'entrée (df) est-elle une trame de données pandas? ou regardez-vous simplement des tableaux numpy?