Initiation à la programmation ENSAE 1A

td_note_2010.tex

File: td_note_2010.tex, line 30


def sous_nuage (nb, x, y, v) :  # retourne une liste de 2-uples

File: td_note_2010.tex, line 35


def n_sous_nuages (n, nb) :     # retourne une liste de 2-uples

File: td_note_2010.tex, line 41


import matplotlib.pyplot as plt
x   = [ ... ]
y   = [ ... ]
fig = plt.figure()
ax  = fig.add_subplot(111)
ax.plot (x,y, 'o')
plt.savefig ("im1.png") # ou plt.show () pour afficher le graphe

File: td_note_2010.tex, line 52


def random_class (points, n) :  # retourne une liste d'entiers

File: td_note_2010.tex, line 67


def proche_barycentre (point, barycentres) :   # retourne un entier

File: td_note_2010.tex, line 72


def association_barycentre (points, barycentres) :  # retourne une liste d'entiers

File: td_note_2010.tex, line 82


def barycentre_classe (points, classes, numero_class) :   # retourne un 2-uple
def tous_barycentres  (points, classes) :       # retourne une liste de 2-uples

File: td_note_2010.tex, line 88


def nuees_dynamiques (points, nombre_classes) : # retourne une liste d'entiers

File: td_note_2010.tex, line 98


import matplotlib.pyplot as plt
x1  = [ ... ]
y1  = [ ... ]
x2  = [ ... ]
y2  = [ ... ]
fig = plt.figure()
ax  = fig.add_subplot(111)
ax.plot (x1,y1, 'o')
ax.plot (x2,y2, 'x')     # ligne ajoutée, 'x', 'bo', ...
plt.savefig ("im2.png")  # 'rx', 'go', 'gs', 'bs', ...

File: td_note_2010.tex, line 133


def n_sous_nuages (n, nb):
    m = []
    for i in range (0,n):
        x = 5*random.random()
        y = 5*random.random()
        d = sous_nuage(nb,x,y,1)
        m += d
    return m

File: td_note_2010.tex, line 146


def n_sous_nuages (n, nb):
    m = []
    for i in range (0,n):
        x = random.randint(0,20)
        y = random.randint(0,20)
        d = sous_nuage(nb,x,y,1)
        m += d
    return m

File: td_note_2010.tex, line 168


def n_sous_nuages (n, nb):
    m = []
    for i in range (0,n):
        x = random.gauss(0,1)
        y = random.gauss(0,1)
        d = sous_nuage(nb,x,y,1)
        m += d
    return m

File: td_note_2010.tex, line 191


def n_sous_nuages (n, nb):
    m = []
    for i in range (0,n):
        x = random.gauss(0,1)
        y = random.gauss(0,1)
        d = sous_nuage(nb,x,y,1)
        m +=  [ d ]                
           # le résultat n'est 
           # plus une liste
    return m

File: td_note_2010.tex, line 209


import matplotlib.pyplot as plt
x = [ p [0] for p in n_sous_nuages (3,50) ] 
y = [ p [1] for p in n_sous_nuages (3,50) ] 
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot (x,y, 'o' )
plt.savefig ("im1.png")

File: td_note_2010.tex, line 223


def random_class(l,n):
    l = []
    for i in range(0,len(l)):
        l += [ random.randint (1,n) ]
    return l

File: td_note_2010.tex, line 234


def random_class(l,n):
    l = []
    for i in range(0,len(l)):
        l += [ random.randint (0,n) ]
    return l

File: td_note_2010.tex, line 245


d= (  (p[0]-f[0])**2+(p[1]-f[1])**2 ) ** (1/2)

File: td_note_2010.tex, line 251


def proche_barycentre (point,barycentres):
    d=distance_euclidienne(point,barycentres[0])
    for i in range (0,len(barycentres)):
        if distance_euclidienne(point,barycentres[i])<=d: 
            d=distance_euclidienne(point,barycentres[i])
    return d

File: td_note_2010.tex, line 265


def barycentre_classe (points, classes, numero_class):
    x=0
    y=0
    for i in range (0,len(classes)):
        if classes[i]==numero_class:  # ligne importante
            l=point[i]
            x=x+l[0]
            y=y+l[1]
    c=[x/n,y/n]                       # ligne importante
    return c

File: td_note_2010.tex, line 284


def tous_barycentres (points,classes):
    c=[]
    for i in classes :   # or on a len(classes) == len(points)
        c+=[barycentre_classe (points,classes,i)]
    return c

File: td_note_2010.tex, line 294


def tous_barycentres (points,classes):
    c=[]
    mx=max(classes)        # il faut ajouter +1
    for i in range(0,mx) : 
        c+=[barycentre_classe (points,classes,i)]
    return c

File: td_note_2010.tex, line 309


def nuees_dynamiques (points,nombre_classes):
    l = random_class (points,nombre_classes)
    for j in range (0,10):
        c = tous_barycentres (points, l)
        a = association_barycentre (points,c)
                        # il faut ajouter ici l = a pour corriger la fonction
    return a

File: td_note_2010.tex, line 321


def nuees_dynamiques (points,nombre_classes):
    for j in range (0,10):
        l = random_class (points,nombre_classes)
        c = tous_barycentres (points, l)
        a = association_barycentre (points,c)
        l = a
    return a

File: td_note_2010.tex, line 333


def nuees_dynamiques (n,nb):
    for j in range (0,10):
        points = n_sous_nuage (n,nb)
        l = random_class (points,nombre_classes)
        c = tous_barycentres (points, l)
        a = association_barycentre (points,c)
        l = a
    return a

, correction 2010

# coding: latin-1
import random
import numpy

def dessin (nuage, image = None) :
    """dessine un nuage de points
    @param      nuage       le nuage de points
    @param      image       si None, on affiche le nuage au travers d'une fenêtre,
                            sinon, image correspond à un nom d'image 
                            sur disque dur qui contiendra le graphique final"""
    import matplotlib.pyplot as plt
    x = [ p[0] for p in nuage ]
    y = [ p[1] for p in nuage ]
    plt.clf ()
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot (x,y, 'o')
    if image == None :  plt.show ()
    else :              plt.savefig (image)
    
def dessin_classes (nuage, classes, image = None) :
    """dessine un nuage, donne des couleurs différentes
    selon que le point appartient à telle ou telle classes
    @param      nuage           nuage[i], c'est le point i
    @param      classes         classes [i] est la classe associée au point i
    @param      image           voir la fonction précédente
    """
    import matplotlib.pyplot as plt
    x = {}
    y = {}
    for i in range (0, len (nuage)) :
        cl = classes [i]
        if cl not in x : 
            x [cl] = []
            y [cl] = []
        x [cl].append ( nuage [i][0] )
        y [cl].append ( nuage [i][1] )
    plt.clf ()
    fig = plt.figure()
    ax = fig.add_subplot(111)
    for cl in x :
        ax.plot (x [cl], y [cl], "+")
    if image == None :  plt.show ()
    else :              plt.savefig (image)
        
def sous_nuage (nb, x, y) :
    """retourne un ensemble de points tirés aléatoirement selon
    une loi normale centrée autour du point x,y
    @param      nb              nombre de points
    @param      x               abscisse du centre
    @param      y               ordonnée du centre
    @return                     une liste de points ou matrice de deux colonnes
                                - la première correspond aux abscisses, 
                                - la seconde aux ordonnées
    """
    res = []
    for i in xrange (0, nb) :
        xx = random.gauss (0,1)
        yy = random.gauss (0,1)
        res.append ( [x+xx, y+yy] )
    return res
    
def n_sous_nuages (nb_class, nb_point) :
    """crée un nuage de points aléatoires 
    @param      nb_class        nombre de sous nuages
    @param      nb_point        nombre de points dans chaque sous nuage
    @return                     une liste de points ou matrice de deux colonnes
                                - la première correspond aux abscisses, 
                                - la seconde aux ordonnées"""
    res = []
    for c in xrange (0, nb_class) :
        x = random.gauss (0,1) * 5
        y = random.gauss (0,1) * 5
        res += sous_nuage (nb_point, x,y)
    return res
    
def random_class ( nuage, n) :  
    """choisis aléatoirement un entier pour chaque point du nuage
    @param      nuage           un nuage de points (matrice de deux colonnes)
    @param      n               nombre de classes
    @return                     une liste d'entiers
    """
    res = [ ]
    for p in nuage :
        c = random.randint (0, n-1)
        res.append (c)
    return res
    
def proche_barycentre (point, barycentres) :
    """détermine le barycentre le plus d'un point 
    @param      point           liste de 2 réels : [x,y]
    @param      barycentres     liste de n points = matrice de deux colonnes,
                                chaque ligne correspond à un barycentre
    @return                     un entier qui correspond à l'index
                                du barycentre le plus proche"""
    dmax = 1e6
    for i in range (0, len (barycentres)) :
        b  = barycentres [i]
        dx = point [0] - b [0]
        dy = point [1] - b [1]
        d  = (dx**2 + dy**2) ** 0.5
        if d < dmax :
            dmax = d
            m    = i
    return m
    
def association_barycentre (points, barycentres) :
    """détermine pour chaque point le barycentre le plus proche
    @param      points          nuage (matrice de deux colonnes)
    @param      barycentres     c'est aussi une matrice de deux colonnes mais
                                avec moins de lignes
    @return                     liste d'entiers, chaque entier
                                correspond à la classe du point points[i],
                                c'est-à-dire l'index du barycentre le plus proche
                                ici: 
                                point:      points [i]
                                classe:     res[i]
                                barycentre: barycentres[ res[i] ]
    """
    res = []
    for p in nuage :
        m = proche_barycentre (p, barycentres)
        res.append (m)
    return res
    
def barycentre_classe (points, classes, numero_class) :
    """calcule le barycentre d'une classe
    @param      points          ensemble de points (matrice de deux colonnes)
    @param      classes         liste d'entiers de même longueur, 
                                chaque élément classes[i] est la classe de point[i]
    @param      numero_class    classe pour laquelle on doit calculer le barycentre
    @return                     résultat barycentre x,y
    
    dans cette fonction, on doit calculer le barycentre d'une classe
    c'est-à-dire le barycentre des points points[i] 
    pour lesquelles classes[i] == numero_class
    """
    mx,my = 0.0,0.0
    nb    = 0
    for i in range (0, len (points)) :
        p = points [i]
        c = classes [i]
        if c != numero_class : continue
        nb += 1
        mx += p [0]
        my += p [1]
    return mx/nb, my/nb
    
def tous_barycentres (points, classes) :
    """calcule les barycentres pour toutes les classes
    @param      points      points, nuage, matrice de deux colonnes
    @param      classes     liste d'entiers
    @return                 liste de barycentre = matrice de deux colonnes 
    """
    mx          = max (classes)+1
    barycentre  = []
    for m in range (0,mx) :
        b = barycentre_classe (points, classes, m)
        barycentre.append (b)
    return barycentre
    
def numpy_tous_barycentres (points, classes) :
    """écriture de barycentre_classe et tous_barycentres
    en une seule fonction avec numpy
    """
    nbcl = max (classes)+1
    mat  = numpy.matrix (points)
    vec  = numpy.array ( classes )
    clas = numpy.zeros ( (len (points), nbcl) )
    for i in range (0, nbcl) : 
        clas [ vec == i, i ] = 1.0 
    nb   = clas.sum (axis = 0)
    for i in range (0, nbcl) : 
        clas [ vec == i, i ] = 1.0 / nb [i]
    ba = mat.transpose () * clas
    ba = ba.transpose ()
    ba = ba.tolist ()
    barycentre = [ b for b in ba ]
    return barycentre
    
def numpy_tous_barycentres2 (points, classes) :
    """écriture de barycentre_classe et tous_barycentres
    en une seule fonction avec numpy
    """
    nbcl        = max (classes)+1
    mat         = numpy.matrix (points)
    matt        = mat.transpose ()
    matcl       = numpy.matrix (classes).transpose ()
    barycentre  = []
    for c in xrange (0, nbcl) :
        w  = numpy.matrix (matcl)
        w [matcl==c] = 1
        w [matcl!=c] = 0
        wt = w.transpose ()
        r  = matt * w
        n  = wt * w
        r /= n [0,0]
        barycentre += [ [ r [0,0], r [1,0] ] ]
        
    return barycentre
    
def nuees_dynamiques (points, nbcl) :
    """algorithme des nuées dynamiques
    @param      points          ensemble points = matrice de deux colonnes
    @param      nbcl            nombre de classes demandées
    @return                     un tableau incluant la liste d'entiers
    """
    classes = random_class (points, nbcl)
    
    # on a le choix entre la version sans numpy
    for i in range (0,10) :
        print "iteration",i, max (classes)+1
        barycentres = tous_barycentres (points, classes)        # ou l'un
        classes     = association_barycentre (points, barycentres)
    cl1 = classes
    
    # ou la première version avec numpy
    for i in range (0,10) :
        print "iteration",i, max (classes)+1
        barycentres = numpy_tous_barycentres (points, classes)  # ou l'autre
        classes     = association_barycentre (points, barycentres)
    cl2 = classes
    
    # ou la seconde version avec numpy
    for i in range (0,10) :
        print "iteration",i, max (classes)+1
        barycentres = numpy_tous_barycentres2 (points, classes)  # ou l'autre
        classes     = association_barycentre (points, barycentres)
    cl3 = classes
    
    # on doit trouver cl1 == cl2 == cl3
    if cl1 != cl2 or cl1 != cl3 :
        print "erreur de calculs dans l'une des trois fonctions"
    return classes
            
# début du programme : on construit un nuage de points
nuage = n_sous_nuages (3, 50)
# on appelle l'algorithme
classes = nuees_dynamiques (nuage, 3)
# on dessine le résultat
dessin_classes (nuage, classes)