prix = 100000 mine = False while True: prix += 20000 print(prix) if prix > 150000 and prix < 200000 and mine == False print("j'achète") mine = True elif prix > 200000 and mine: print("Je revends") mine = False break prix = 100000 mine = False while True: prix += 20000 print(prix) if prix > 150000 and prix < 200000 and mine == False: print("j'achète") mine = True elif prix > 200000 and mine: print("Je revends") mine = False break prices = [50000, 1000, 500000, 200000, 300000, 400000, 260000, 270000] #Boucle: filtered = [] for p in prices: if p >= 200000 and p <= 300000: filtered.append(p) #List-comprehension: filtered = [p for p in prices if p >= 200000 and p <= 300000 ] print(filtered) #df["large_houses"] = df.surface > df.surface.median() #df.groupby("large_houses")["price"].describe() #ou: (il n'est pas nécessaire d'ajouter une colonne dans le dataframe, #il suffit de donner comme argument du groupby une series de la même longueur que le dataframe) is_large = df.surface > df.surface.median() df.groupby(is_large)["price"].describe() #ou directement: df.groupby(df.surface > df.surface.median())["price"].describe() #Bonus: Anova #Pour avoir un code générique, ou extrait tous les groupes obtenus sous forme d'une liste groups = df.groupby(is_large)["price"] group_list = [g[1].values for g in groups] #La méthode f_oneway prend autant d'arguments que d'échantillon à comparer. Pour transformer une liste en arguments, on utilise le symbole * stats.f_oneway(*group_list) #Bonus: corrélation df[["price","surface"]].corr() #Bonus: scatter plot (plus de détails au chapitre suivant) df.plot.scatter("surface","price") #Inter-quantile range Q1 = df.price.quantile(0.25) Q3 = df.price.quantile(0.75) IQR = Q3 - Q1 h = 2 print("limits:", (Q1 - h * IQR), "to", (Q3 + h * IQR)) #Les données s'écartant fortement des quantiles sont potentiellement des anomalies (outlier en anglais) is_outlier = (df.price < (Q1 - h * IQR)) | (df.price > (Q3 + h * IQR)) df.loc[is_outlier] def detect_outliers(df, column, h = 2, left = 0.25, right = 0.75): Q1 = df[column].quantile(left) Q3 = df[column].quantile(right) IQR = Q3 - Q1 #print("limits:", (Q1 - h * IQR), "to", (Q3 + h * IQR)) #Les données s'écartant fortement des quantiles sont potentiellement des anomalies (outlier en anglais) is_outlier = (df[column] < (Q1 - h * IQR)) | (df[column] > (Q3 + h * IQR)) outliers = df.loc[is_outlier] if len(outliers) > 0: print("Anomalies en terme de", column, ":") display(outliers) return outliers out = detect_outliers(df, 'price') out = detect_outliers(df, 'surface') def detect_outliers(df, column, h = 2, left = 0.25, right = 0.75): """ df: un DataFrame pandas col: nom de la colonne du dataframe à analyser (string) """ #On peut éventuellement vérifier les types des arguments if type(column) != str: raise Exception("L'argument 'col' doit être un string") #l'instruction "assert" permet de directement générer une exception si une condition n'est pas respectée: #assert , assert type(column) == str, "L'argument 'col' doit être un string" assert type(df) == pd.DataFrame, "L'argument 'df' doit être un DataFrame pandas" Q1 = df[column].quantile(left) Q3 = df[column].quantile(right) IQR = Q3 - Q1 #print("limits:", (Q1 - h * IQR), "to", (Q3 + h * IQR)) #Les données s'écartant fortement des quantiles sont potentiellement des anomalies (outlier en anglais) is_outlier = (df[column] < (Q1 - h * IQR)) | (df[column] > (Q3 + h * IQR)) outliers = df.loc[is_outlier] if len(outliers) > 0: print("Anomalies en terme de", column, ":") display(outliers) return outliers out = detect_outliers(df, 'price') out = detect_outliers(df, 'surface') #Erreur d'assertion try: out = detect_outliers(42, 'surface') except Exception as e: print(e) #variables catégorielles (le nombre de chambres peut être considéré comme variable catégorielle aussi) def detect_rare_cat(df, column, nmin = 2): """ Cette fonction permet de détecter des outliers dans des variables catégorielles """ counts = df.groupby(column)['price'].count() rare_cats = counts[counts < nmin] outliers = df[df[column].isin(rare_cats.index)] if len(outliers) > 0: print("Anomalies en terme de", column, ":") display(outliers) return outliers out = detect_rare_cat(df, 'city') def is_cat(series, relative_threshold = 0.5, absolute_threshold = 20): nvalues = len(series) ncats = len(series.unique()) #On considère la variable comme catégorielle si le nombre de valeurs uniques et plus petit qu'un seuil relatif ou absolu return (ncats/nvalues <= relative_threshold) and (ncats <= absolute_threshold) def is_num(series): try: series.astype(float) return True except: return False is_categorical = df.apply(is_cat) is_numeric = df.apply(is_num) is_numeric cols = df.columns for col in cols: #Détection d'outliers pour les variables catégorielles if is_cat(df[col]): outliers = detect_rare_cat(df, col) if len(outliers) == 0: print("No categorical outlier detected for columns", col) #Détection d'outliers pour les variables numériques if is_num(df[col]): outliers = detect_outliers(df, col) if len(outliers) == 0: print("No numeric outlier detected for columns", col) cat_cols = is_categorical[is_categorical == True].index num_cols = is_numeric[is_numeric == True].index #Pour chaque colonne catégorielle, on extrait lest outliers cat_outliers = [detect_rare_cat(df, cat) for cat in cat_cols] #rassemblons les outliers dans un seul dataframe (nous pouvons retirer les doublons) cat_outliers = pd.concat(cat_outliers).drop_duplicates() #Pour chaque colonne numérique, on extrait les outliers num_outliers = [detect_outliers(df, c) for c in num_cols] #Rassemblons les outliers trouvés dans un seul dataframe num_outliers = pd.concat(num_outliers).drop_duplicates() #Rassemblons tous les outliers outliers = pd.concat([num_outliers, cat_outliers]).drop_duplicates() print("Tous les outliers:") display(outliers) #On supprime les outliers (à partir de leur index) df_filtered = df.drop(outliers.index) print("Dataframe filtré:") display(df_filtered) #Définissons des fonctions de détection d'outliers sur des Series, pour pouvoir utiliser la méthode "apply" dessus: def is_cat(series, relative_threshold = 0.5, absolute_threshold = 20): nvalues = len(series) ncats = len(series.unique()) #On considère la variable comme catégorielle si le nombre de valeurs uniques et plus petit qu'un seuil relatif ou absolu return (ncats/nvalues <= relative_threshold) and (ncats <= absolute_threshold) def is_num(series): try: series.astype(float) return True except: return False #Détection d'outliers numériques def detect_numeric_outliers_series(series, h = 2, left = 0.25, right = 0.75): Q1 = series.quantile(left) Q3 = series.quantile(right) IQR = Q3 - Q1 #Les données s'écartant fortement des quantiles sont potentiellement des anomalies (outlier en anglais) is_outlier = (series < (Q1 - h * IQR)) | (series > (Q3 + h * IQR)) if is_outlier.sum() > 0: print(is_outlier.sum(), "outliers numériques trouvés pour", series.name) return is_outlier #Détection d'outliers catégoriels: on identifie une catégorie rare si elle représente moins de 1% (seuil relatif) des données def detect_rare_cat_series(series, relative_threshold = 0.01, nmin = 2): counts = series.value_counts() #on garde la contrainte la plus souple (< rel_th% des données, ou < nmin) relative_nmin = relative_threshold*len(series) tot_nmin = max(nmin, relative_nmin) is_rare = (counts < tot_nmin) rare_cats = counts[is_rare] is_outlier = series.isin(rare_cats.index) if is_outlier.sum() > 0: print(is_outlier.sum(), "outliers catégoriels trouvés pour", series.name) return is_outlier #Détection générique des outliers dans une Series def detect_outlier_series(series): """ Il vaut mieux privilégier la représentation catégorielle plutôt que numérique. En effet, si il existe peu de valeurs différentes, la détection numérique peut ne pas être efficace: E.G.: pour une variable binaire dont 20% des données sont 0, on détectera 20% d'outliers (IQR = 0) """ if is_cat(series): return detect_rare_cat_series(series) elif is_num(series): return detect_numeric_outliers_series(series) else: #return a Series containing only False return pd.Series(False, series.index) outliers = df.apply(detect_outlier_series) #De cette manière, on peut observer le nombre de fois qu'une maison est considérée comme anormale outlier_sum = outliers.sum(axis = 1) outlier_sum.plot.bar() plt.xticks(range(len(df.address)), labels = df.address, rotation = "vertical") #On peut vérifier pour quelles variables chaque maison est considérée comme anormale display(outliers) #Outliers n_cols = 2 display(df[outlier_sum >= n_cols])