Python et animation — Les-mathematiques.net The most powerful custom community solution in the world

Python et animation

Bonjour
Le code suivant est plutôt simple, il s'agit à partir d'un tableau de moyennes et d'un tableau de covariance d'afficher de manière animée un nuage de points et des lignes de niveaux de la densité gaussiennes en dimension $2$.

Alors le tableau de moyennes est un tableau de vecteurs de taille $3 \times 2$ parce qu'en fait, j'ai trois nuages [de] gaussiennes donc mu[k] est la moyenne du nuage k.
Pour les matrice de covariance qui sont $2 \times 2$ mais en fait $3 \times 2 \times 2$ parce que j'ai trois nuages.

Quelle a été ma méthode ?
1) Je commence par faire une grille.

2) Comme le tableau des moyennes est trop grand (donc aussi le tableau des variances car ils ont la même taille) alors je ne sélectionne que quelques indices, je prends le premier et le dernier indice puis je prends les autres indices au hasard uniformément entre les deux.

3) Je crée une liste deux dimensionnelles qui Zmes[ i][k] c'est les valeurs sur la grille de la gaussienne de paramètre mu[ i][k] et Sigma[ i][k].
Par exemple pour i disons 120 je prends la moyenne numéro 120 dans mon tableau et la variance numéro 120.
Et comme ces cases contiennent en fait 3 moyennes (et 3 variances) je peux calculer les valeurs de 3 densités gaussiennes Zmes[120][k] pour k = 0, 1 et 2.

4) On affiche.

L'étape qui ne marche pas est ... la 3) bien sûr, pourquoi ? Ben Zmes[ i] est le même pour tout i ! je ne comprend pas pourquoi. D'ailleurs une fois qu'on aura réglé ce problème je suis ouvert aussi pour améliorer la qualité de mon code :).
Bonne journée !
Voici le code.
def f_display(mu_tab, sigma_tab, sample):
  print("Fin de l'algorithme EM, début de l'affichage")
  # Préparation de la grille
  l_sample = len(sample)
  xmin = np.min(np.array([sample[ i][0] for i in range(l_sample)]))
  xmax = np.max(np.array([sample[ i][0] for i in range(l_sample)]))
  x = np.linspace(xmin - 3 , xmax + 5, 75)
  ymin = np.min(np.array([sample[ i][1] for i in range(l_sample)]))
  ymax = np.max(np.array([sample[ i][1] for i in range(l_sample)]))
  y = np.linspace(ymin - 3, ymax + 5, 75)
  Xmesh,Ymesh = np.meshgrid(x,y)

  # Selection d'un certain nombres de paramètres qu'on affichera ensuite
  total_step = len(mu_tab)
  C = len(mu_tab[0])
  nb_display = 10
  display_tab = stats.randint(0, total_step).rvs(size = nb_display - 2)
  display_tab = np.concatenate( ([0], np.sort(display_tab), [total_step-1]), axis = None)
  
  # On calcul les densités
  Zmesh = [[0]*C]*nb_display
  step = 1
  for disp in display_tab:
    print("étape {}/{}".format(step, nb_display))
    step = step +1
    Z = np.zeros( [len(Xmesh),len(Ymesh)] )
    for k in range(3):
        Z = np.zeros( [len(Xmesh),len(Ymesh)] )
        for i in range(len(x)):
          for j in range(len(y)):
            Z[ i][j] = stats.multivariate_normal(mu_tab[disp][k], sigma_tab[disp][k]).pdf([Xmesh[ i,j],Ymesh[ i,j]])
        Zmesh[step-2][k] = Z

  clear_output()

  # Affichage les lignes de niveaux gaussiennes
  for disp in range(nb_display):
    plt.figure(figsize = [20,10])
    # Affichage du nuage de points
    for indice in range(3):
      plt.scatter(sample_X[indice],sample_Y[indice])
    # Affichage des lignes de niveaux
    for k in range(3):
      plt.contour(Xmesh,Ymesh,Zmesh[disp][k],levels=14, cmap = 'RdGy')
    plt.title("Ligne de niveaux à l'étape {}/{}".format(display_tab[disp], total_step-1))
    plt.show()
    time.sleep(2)
    clear_output(wait = True)

Réponses

  • Ton Zmesh a l'air de souffrir du phénomène expliqué ici. Tu devrais probablement l'initialiser ainsi afin que ses éléments ne pointent pas tous vers le même objet :
    Zmesh = [ [0]*C for _ in range(nb_display) ]
    
  • merci !
  • Du coup c'est bon, je poste ma solution car je suis ouvert aux critiques.
    def f_display(mu_tab, sigma_tab, sample):
      # Préparation de la grille
      l_sample = len(sample)
      xmin = np.min(np.array([sample[ i][0] for i in range(l_sample)]))
      xmax = np.max(np.array([sample[ i][0] for i in range(l_sample)]))
      x = np.linspace(xmin - 3 , xmax + 5, 75)
      ymin = np.min(np.array([sample[ i][1] for i in range(l_sample)]))
      ymax = np.max(np.array([sample[ i][1] for i in range(l_sample)]))
      y = np.linspace(ymin - 3, ymax + 5, 75)
      Xmesh,Ymesh = np.meshgrid(x,y)
    
      # Selection d'un certain nombres de paramètres qu'on affichera ensuite
      total_step = len(mu_tab)
      C = len(mu_tab[0])
      nb_display = min(10, total_step-1)
      print(nb_display)
      display_tab = list(np.random.permutation(np.arange(1,total_step-1))[:nb_display-2])
      display_tab = np.concatenate( ([0], np.sort(display_tab), [total_step-1]), axis = None)
      
      # On calcul les densités
      Zmesh = [ [0]*C for _ in range(nb_display) ]
      # Problème voir ici : http://www.les-mathematiques.net/phorum/read.php?15,1958182 
      step = 1
      for disp in display_tab:
        print("étape {}/{}".format(step, nb_display))
        step = step +1
        for k in range(3):
            Z = np.zeros( [len(Xmesh),len(Ymesh)] )
            for i in range(len(x)):
              for j in range(len(y)):
                Z[ i][j] = stats.multivariate_normal(mu_tab[disp][k], sigma_tab[disp][k]).pdf([Xmesh[ i,j],Ymesh[ i,j]])
            Zmesh[step-2][k] = Z
    
      clear_output()
    
      # Affichage les lignes de niveaux gaussiennes
      for disp in range(nb_display):
        plt.figure(figsize = [20,10])
        # Affichage du nuage de points
        for indice in range(3):
          plt.scatter(sample_X[indice],sample_Y[indice])
        # Affichage des lignes de niveaux
        for k in range(3):
          plt.contour(Xmesh,Ymesh,Zmesh[disp][k],levels=14, cmap = 'RdGy')
        plt.title("Ligne de niveaux à l'étape {}/{}".format(display_tab[disp], total_step-1))
        plt.show()
        time.sleep(2)
        clear_output(wait = True)
    
Connectez-vous ou Inscrivez-vous pour répondre.
Success message!