Roulitoo / cours_iae

5 stars 4 forks source link

Question ESD test #5

Open maw85 opened 1 year ago

maw85 commented 1 year ago

Bonjour Monsieur,

Avez-vous déjà utilisé le ESD test pour la détection de plusieurs outliers ?

En effet, nous n'arrivons pas à le faire fonctionner. Nous avons des problèmes d'index dont nous ne comprenons pas la source, et nous nous trouvons pas d'aide sur internet par rapport à cela.

Voici le code que nous avons utilisé le code suivant (https://github.com/bhattbhavesh91/outlier-detection-grubbs-test-and-generalized-esd-test-python/blob/master/generalized-esd-test-for-outliers.ipynb) :

def grubbs_stat(y): std_dev = np.std(y) avg_y = np.mean(y) abs_val_minus_avg = abs(y - avg_y) max_of_deviations = max(abs_val_minus_avg) max_ind = np.argmax(abs_val_minus_avg) Gcal = max_of_deviations/ std_dev print("Grubbs Statistics Value : {}".format(Gcal)) return Gcal, max_ind

def calculate_critical_value(size, alpha): t_dist = stats.t.ppf(1 - alpha / (2 size), size - 2) numerator = (size - 1) np.sqrt(np.square(t_dist)) denominator = np.sqrt(size) * np.sqrt(size - 2 + np.square(t_dist)) critical_value = numerator / denominator print("Grubbs Critical Value: {}".format(critical_value)) return critical_value

def check_G_values(Gs, Gc, inp, max_index): if Gs > Gc: print('{} is an outlier. G > G-critical: {:.4f} > {:.4f} \n'.format(inp[max_index], Gs, Gc)) else: print('{} is not an outlier. G > G-critical: {:.4f} > {:.4f} \n'.format(inp[max_index], Gs, Gc))

def ESD_Test(input_series, alpha, max_outliers): for iterations in range(max_outliers): Gcritical = calculate_critical_value(len(input_series), alpha) Gstat, max_index = grubbs_stat(input_series) check_G_values(Gstat, Gcritical, input_series, max_index) print(input_series) print(max_index) input_series = np.delete(input_series, max_index)

ESD_Test(df5['critics_vote'], 0.05, 4) #exemple pour notre cas pour cette ligne

ValueError: Length of values (18217) does not match length of index (18218)

Nous avons dans notre base (après nettoyage) 18 218 observations.

Lorsque nous testons le code avec le jeu de données présent dans le github de la personne, cela fonctionne. Mais à partir du moment où nous passons sur d'autres bases (pour ce projet et d'autres), nous avons des problèmes. Nous ne comprenons pas comment résoudre ce problème. Sauriez-vous nous aider ?

Merci d'avance et belle fin de journée, François et Emma.W

Roulitoo commented 1 year ago

Bonsoir,

Votre exemple n'est pas reproductible donc difficile de voir d'où vient l'erreur exactement. 'DF5' n'est pas un objet disponible pour que je puisse le tester.

En revanche, votre code pour le test ESD est fait pour prendre en entrer un numpy array et non pas un pandas.core.series.Series.

Je vous laisser tester ca :


type(y)
type(df5['critics_vote'])
#Regarder la différence de type 

#Transformer le type de df5['critics_vote'] pour le rendre en np.array avec la commande 

test_y = np.array(df5['critics_vote'])
ESD_Test(test_y , 0.05, 4) 

Je vous laisse regarder dans vos fonctions pourquoi vous avez une erreur de la taille de l'index si vous utilisez un pandas.core.series.

Bonne soirée

BambelLarry commented 1 year ago

Bonsoir Monsieur,

Merci à vous pour votre réponse, le test fonctionne désormais correctement. Effectivement, avec un pandas.core.series la fonction np.delete ne fonctionne pas et créé une erreur.

J'ai amélioré (rien d'impressionnant) la fonction test ESD pour que les résultats soient plus visuels et adaptés à notre problématique (avec pandas.core.series en entrée).

def grubbs_stat(y):
    std_dev = np.std(y)
    avg_y = np.mean(y)
    abs_val_minus_avg = abs(y - avg_y)
    max_of_deviations = max(abs_val_minus_avg)
    max_ind = np.argmax(abs_val_minus_avg)
    Gcal = max_of_deviations/ std_dev
    #print("Grubbs Statistics Value : {}".format(Gcal))
    return Gcal, max_ind

def calculate_critical_value(size, alpha):
    t_dist = stats.t.ppf(1 - alpha / (2 * size), size - 2)
    numerator = (size - 1) * np.sqrt(np.square(t_dist))
    denominator = np.sqrt(size) * np.sqrt(size - 2 + np.square(t_dist))
    critical_value = numerator / denominator
    #print("Grubbs Critical Value: {}".format(critical_value))
    return critical_value

#ESD test
def ESD_Test(input_series, alpha, max_outliers):
    input_series = np.array(input_series) #Transformation de la colonne en array

    #Initialisation des valeurs
    nb_outliers=0
    valeur_atypique_seuil="-"

    #Itération pour chaque valeur de la série
    for iterations in range(max_outliers):
        Gcritical = calculate_critical_value(len(input_series), alpha)
        Gstat, max_index = grubbs_stat(input_series)

        #Récupère les valeurs de la dernière itération où la valeur est considéré comme atypique
        if round(Gstat,4)>round(Gcritical,4) :
            nb_outliers+=1
            valeur_atypique_seuil=input_series[max_index]
            last_Gstat=Gstat
            last_Gcritical=Gcritical

        #Supprime la valeur de l'itération pour tester sur d'autres
        input_series = np.delete(input_series, max_index)

    #Print des résultats du test
    print("Nombre de valeurs atypiques : "+ str(nb_outliers))
    print("Valeur atypique seuil : {}".format(valeur_atypique_seuil))

    if nb_outliers>0 :
        print('{} is an outlier. G > G-critical: {:.4f} > {:.4f} \n'.format(valeur_atypique_seuil, last_Gstat, last_Gcritical))

    if (max_outliers*0.8)<nb_outliers : #Marge de sécurité
        print('\033[1m' + "Veuillez augmenter le nombre d'outlier max par sécurité"+'\033[0m')

    return valeur_atypique_seuil

ESD_Test(df['duration'] , 0.05, 5)

Néanmoins, il faut faire attention aux variables avec des valeurs atypiques à la fois faibles et élevés (des 2 côtés). Je ne sais pas comment ce test gère ces cas-là ni sur Python, ni sur R.

Joyeuses fêtes,

François