Je suis un débutant avec Python et la programmation en général. J'essaie d'écrire un programme qui itère à travers un tableau numpy spécifique et détecte les anomalies dans l'ensemble de données (la définition d'une anomalie est tout point supérieur à 3 fois l'écart type de la moyenne SANS le point de données). Je dois recalculer la moyenne et l'écart type pour chaque fois qu'un point de données anormal est supprimé.
J'ai écrit le code ci-dessous, mais j'ai remarqué quelques problèmes. Une fois la boucle répétée une fois, il indique que la valeur de 160 est supprimée, mais lorsque j'imprime new_array, je vois toujours 160 dans le tableau.
De plus, comment puis-je recalculer la nouvelle moyenne pour chaque fois qu'un point de données est supprimé? J'ai l'impression que quelque chose est juste mal positionné dans la boucle for. Et enfin mon utilisation de continue est-elle correcte ou doit-elle être placée ailleurs?
import numpy as np
data_array = np.array([
99.5697438 , 94.47019021, 55., 106.86672855,
102.78730151, 131.85777845, 88.25376895, 96.94439838,
83.67782174, 115.57993209, 118.97651966, 94.40479467,
79.63342207, 77.88602065, 96.59145004, 99.50145353,
97.25980235, 87.72010069, 101.30597215, 87.3110369 ,
110.0687946 , 104.71504012, 89.34719772, 160.,
110.61519268, 112.94716398, 104.41867586])
for cell in data_array:
mean = np.mean(data_array, axis=0)
sd = np.std(data_array, axis=0)
lower_anomaly_point = mean - (3 * sd)
upper_anomaly_point = mean + (3 * sd)
if cell > upper_anomaly_point or cell < lower_anomaly_point:
print(str(cell) + 'has been removed.')
new_array = np.delete(data_array, cell)
continue
3 Réponses :
Comme @damagedcoda le dit, votre erreur principale est que vous devriez utiliser index à la place de la valeur, mais vous aurez un nouveau problème si vous recalculez le lower_anomaly_point et le upper_anomaly_point à l'intérieur du cycle. Je vous recommande donc d'essayer le np.where pour résoudre votre tâche:
array([ 99.5697438 , 94.47019021, 55. , 106.86672855,
102.78730151, 131.85777845, 88.25376895, 96.94439838,
83.67782174, 115.57993209, 118.97651966, 94.40479467,
79.63342207, 77.88602065, 96.59145004, 99.50145353,
97.25980235, 87.72010069, 101.30597215, 87.3110369 ,
110.0687946 , 104.71504012, 89.34719772, 110.61519268,
112.94716398, 104.41867586])
et le résultat est:
import numpy as np
data_array = np.array([
99.5697438 , 94.47019021, 55., 106.86672855,
102.78730151, 131.85777845, 88.25376895, 96.94439838,
83.67782174, 115.57993209, 118.97651966, 94.40479467,
79.63342207, 77.88602065, 96.59145004, 99.50145353,
97.25980235, 87.72010069, 101.30597215, 87.3110369 ,
110.0687946 , 104.71504012, 89.34719772, 160.,
110.61519268, 112.94716398, 104.41867586])
mean = np.mean(data_array, axis=0)
sd = np.std(data_array, axis=0)
lower_anomaly_point = mean - (3 * sd)
upper_anomaly_point = mean + (3 * sd)
data_array = data_array[
np.where(
(upper_anomaly_point > data_array) & (data_array > lower_anomaly_point)
)]
Ce code échoue pour moi. Le data_array ne change pas, np.delete renvoie un nouveau tableau, il ne change pas l'ancien. Vous n'utilisez new_array à aucun endroit du code, vous vouliez probablement calculer la moyenne à partir de new_array Le deuxième argument de la suppression doit être index, "indique le sous-tableau à supprimer". vous ne pouvez pas utiliser la cellule.
import numpy as np
data_array = np.array([
99.5697438 , 94.47019021, 55., 106.86672855,
102.78730151, 131.85777845, 88.25376895, 96.94439838,
83.67782174, 115.57993209, 118.97651966, 94.40479467,
79.63342207, 77.88602065, 96.59145004, 99.50145353,
97.25980235, 87.72010069, 101.30597215, 87.3110369 ,
110.0687946 , 104.71504012, 89.34719772, 160.,
110.61519268, 112.94716398, 104.41867586])
mean = np.mean(data_array, axis=0)
sd = np.std(data_array, axis=0)
lower_anomaly_point = mean - (3 * sd)
upper_anomaly_point = mean + (3 * sd)
new_array = data_array.copy()
k = 0
for i, cell in enumerate(data_array):
if cell > upper_anomaly_point or cell < lower_anomaly_point:
print(str(cell) + 'has been removed.')
new_array = np.delete(new_array, i - k)
k += 1
new_array est data_array sans 160. comme vous le souhaitiez
Je pense que vous devriez voir Documentation Numpy et se réfèrent à la première ligne où ils disent spécifiquement qu'il renvoie tous les éléments qui ne sont pas conformes à arr [obj], cela signifie que numpy.delete () fonctionne dans un index manière basée.
Je vous suggère de modifier votre code afin d'obtenir l'index de cette cellule, puis de le transmettre à np.delete()
Voici le code modifié:
import numpy as np
data_array = np.array([99.5697438, 94.47019021, 55.0, 106.86672855, 102.78730151, 131.85777845, 88.25376895, 96.94439838, 83.67782174, 115.57993209, 118.97651966, 94.40479467, 79.63342207, 77.88602065, 96.59145004, 99.50145353, 97.25980235, 87.72010069, 101.30597215, 87.3110369, 110.0687946, 104.71504012, 89.34719772, 160.0, 110.61519268, 112.94716398, 104.41867586])
print(data_array)
for cell in data_array:
mean = np.mean(data_array, axis=0)
sd = np.std(data_array, axis=0)
lower_anomaly_point = mean - (3 * sd)
upper_anomaly_point = mean + (3 * sd)
if cell > upper_anomaly_point or cell < lower_anomaly_point:
print(str(cell) + 'has been removed.')
index=np.where(data_array==cell)
new_array = np.delete(data_array, obj=index)
continue
Le problème avec votre code actuel (même si vous corrigez les erreurs) est que les valeurs qui ont été vérifiées en premier peuvent se trouver en dehors de la nouvelle marge, après la suppression d'une entrée. Cela signifie que votre code peut ne pas toujours renvoyer des résultats corrects. Je vous conseillerais de faire ces étapes avec une boucle while: Tant qu'il y a une valeur aberrante, qui est en dehors de la marge
3 * std: 1. Trouvez la valeur aberrante, qui est la plus éloignée demeanet supprimez-le 2. Calculez les nouveauxmeanetstd