IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

optimisation fichier long


Sujet :

Python

  1. #41
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Si je comprends bien, ekremy, tu as abaissé ton objectif parce que ça ramait. Mais diviser par 2 un temps trés long, ça ne fait encore qu'un temps très long.

    Pour ma part, je pense qu'il faut envisager les choses le plus globalement possible d'abord, et donc choisir son objectif et s'y tenir. Ce ne sera pas le même algorithme si tu veux comparer toutes les lignes ou seulement les suivantes d'une ligne. Une fois obtenu le programme pour comparer les lignes suivantes, il ne faut pas penser qu'il suffira de remplacer for j in d[n:] par for j in range(len(d)) pour obtenir un programme tout beau qui comparera toutes les lignes entre elles.
    C'est avant qu'il faut décider.
    Que veux tu faire ? Comparer toutes les lignes ? C'est ce qui me parait le plus logique.
    Je dis bien : comparer une ligne avec toutes les autres lignes = avec les précédentes ET avec les suivantes.


    J'ai même pensé qu'il faudrait peut être prendre les choses plus en amont.
    D'où provient le fichier mat1 ?
    Est-ce un fichier qui t'est fourni tout ficelé, ou bien est-ce toi qui le crée ? Parce que si tu crées toi même le fichier, c'est dommage de disposer de données dans des variables au moment de sa création et de ne faire aucun traitement dessus qui pourrait faciliter les choses ultérieurement, c'est à dire avec ton présent problème.

  2. #42
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Je n'ai pas assez lu ton message #40 avant d'écrire mon précédent.
    J'ai beau le relire, je ne comprends pas.

    après qu'on calcule chaque dice pour le motA avec tous les autres mots.
    On ne calcule pas chaque dice pour le mot A, on calcule tous les dice(motA,motX) de mot A avec tous les autres motX

    mais aussi
    <B>A</B>
    <C>A</C>
    Tu veux dire qu'après avoir écrit <A>B##C</A> dans le fichier f1, tu écris aussi <B>A</B> et
    <C>A</C> ?


    ce qui permet de gérer la symétrie.
    C'est à dire ? La gérer quand ?

    j'ai crée une fonction qui permet de réunifier la liste de tous les mots identiques.
    la liste ? pour l'écrire dans un autre fichier encore ? pour la traiter avec un programme ? pour quoi faire ?

    je te propose une chose:
    au lieu de parler de motA motB motC et de dice(motA,motW)
    de parler plutôt en indices:
    mot i, mot i+1.....dice(2,78) etc..

  3. #43
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    J'ai pu télécharger et enregistrer sur mon disque dur le fichier de 64 Mo mais il est en Word, si bien que je ne peux pas l'ouvrir avec un programme Python.
    Je ne sais pas non plus changer le type du fichier pour en faire un fichier lisible par un programme Python.


    Autre question importante sur ton programme:
    Comment est fixée la valeur de m ? Est-ce un entier fixe ? Sa valeur dépend elle de lcountlist et des valeurs de dices y contenues ?

  4. #44
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    le fichier mat1, c'est moi qui le crée.
    En effet, vu que ça me prenait pas mal de temps à executer mon pg, je me suis dit,directement executer mon programme sur un fichier tout prêt.

    Le fichier Mat1 provient d'un dico tout simplement.
    par ex:

    dico = {"A:{1,2,3,4}","B:{2,4,7,9}","C:{1,4,7,9}}
    ce que j'ai fait, c'est parcourir le dico et j'écris dans le fichier sous ce format :
    <cle>valeur#valeur</cle>

    je pense aussi qu'il est logique de comparer les valeurs précédentes et suivantes mais comme je te l'ai dit, j'ai pas réussi à trouver d'algo assez costaud. tu me diras même avec l'autre méthode, ce n'est pas aussi rapide.

    Je vais t'expliquer comment je crée ce dico pour vraiment comprendre le concept

    Au départ, J'ai deux fichiers qui me sont fournis, ce sont des corpus de texte avec {S} qui est un délimiteur de phrase.
    Je traite ces deux fichiers en mêmes temps. je récupère pour chaque phrase les mots simples (qui se trouve dans un fichier) et les mots composés (qui se trouve dans l'autre fichier)
    à la fin j'obtiens un dico
    qui ressemble à ça :

    dico = {1:{A,B,C,D,E};2{A,C,D,E};3{B,D,E}} : ça signifie
    que la phrase 1 contient la liste des mots A,B,C,D,E et ainsi de suite.
    Ensuite je parcours ce dico pour stocker pour chaque mot la liste des phrases où il apparait.

    donc j'obtiens le dico suivant :
    dico = {A:{1,2};B:{1,3};C:{1,2};D:{1,2,3};E:{1,2,3}}

    et c'est à partir de là, que j'écris mon dico dans le fichier.

    j'espère que là, tu vois un peu mieux le pb du projet


    pour répondre à ton dernier post :

    on calcule bien tous les dice(motA,motX) de mot A avec tous les autres motX

    mais aussi
    <B>A</B>
    <C>A</C>
    Tu veux dire qu'après avoir écrit <A>B##C</A> dans le fichier f1, tu écris aussi <B>A</B> et
    <C>A</C> ?

    ce qui permet de gérer la symétrie.
    C'est à dire ? La gérer quand ?

    OUI, j'écris de cette manière pour gérer la symétrie
    L'exemple ci dessus illustre bien la symétrie.
    Quand je compare A avec B, après que je calcule DICE, je stocke B comme cooccurent de A, mais je dois aussi stocker A comme cooccurent de B.
    Mais si on prend le choix de comparer les lignes avec leur précédentes, cette étape ne servira plus à rien car on va calculer dice (A,B) mais par la suite aussi dice (B,A)

    j'ai crée une fonction qui permet de réunifier la liste de tous les mots identiques.
    la liste ? pour l'écrire dans un autre fichier encore ? pour la traiter avec un programme ? pour quoi faire ?


    Le résultat de l'algo devra être stocké dans un fichier obligatoirement car le calcul étant long (à priori, d'après le prof, ça dure 1h30), lors de la soutenance, on devra utiliser ce fichier de résultat pour tester un pg.

    donc le résultat doit bien être dans un fichier, ensuite la forme c'est moi qui l'ai choisit pour facilter la recherche d'info:
    <A>B#C</A>
    <B>A</B>
    <C>A#M</C>
    etc.....

    donc comme j'avais choisi de parcourir juste les mots suivants, j'obtenais dans mon fichier de sortie :

    <A>B##C</A>
    <B>A</B>
    <C>A</C>
    <B>M,Z</B>
    <C>P,Y</C>
    et donc je dois faire un autre pg pour réunir

    <A>B##C</A>
    Pour B
    <B>A,M,Z</B>
    Pour C
    <C>A,P,Y</C>

    mais le code de réunification :

    je parcours la ligne,
    <A>B##C</A>
    je récupère <A>
    je recherche dans tout le texte toutes lignes qui commence par <A> et je récupère leur liste pour chaque ligne
    puis j'écris dans un fichier
    ensuite A je le met dans une liste qui me permet de savoir que je l'ai déjà traité.
    et ainsi de suite.
    ça a l'air d'être rapide quand meme.
    mais c'est pas mon souci, c'est créer cette matrice de cooccurrence

  5. #45
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    la valeur m, c'est moi qui la fixe
    je met 20

  6. #46
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Pourquoi comparer un mot avec tous les autres ? Il suffit de le comparer avec les mots qui apparaissent aux mêmes lignes; les autres auront un 'dice' de 0 de toute façon.

    A partir des deux dicos que, si j'ai bien compris, tu as déjà construit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    dico1 = { 1:['A','B','C','D','E'], 2:['A','C','D','E'], 3:['B','D','E'] }
    dico2 = { 'A':[1,2], 'B':[1,3], 'C':[1,2], 'D':[1,2,3], 'E':[1,2,3]}
    (J'ai juste transformé ton exemple dans une syntaxe Python valide)

    'A' se trouve aux phrases 1 et 2. Il suffit donc de compter mots qui se trouvent aux phrases 1 et 2, qu'on retrouvent à partir de dico1.
    Dans ce genre là:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    dico3 = {}
    for mot, phrases in dico2.items():
       counts = defaultdict(int)
       dico3[mot] = counts
        for phrase in phrases:
            for autre_mot in dico1[phrase]:
                counts[autre_mot] += 1
    Cela me semble beaucoup plus efficace comme algorithme. Après, il faut voir si l'utilisation mémoire reste raisonnable... Pour gagner de la place, on pourrait écraser les entrées de dico2 au lieu de créer un troisième dico, vu qu'on n'a plus besoin d'une entrée après l'avoir traitée.

  7. #47
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Avec le fichier mat1.log, j'ai fait tourner le programme suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    from collections import defaultdict
    import re
     
    filename = "c:\\tmp\\mat1.log"
    motif = re.compile(r"</|>|<|#+")
     
    f = file(filename)
    dico2 = {}
    for line in f:
        l = motif.split(line)
        dico2[l[1]] = map(int,l[2:-2])
    f.close()
     
    print "dico2 généré"
     
    dico1 = defaultdict(list)
    for mot, phrases in dico2.iteritems():
        for phrase in phrases:
            dico1[phrase].append(mot)
     
    print "dico1 généré"
     
    dico3 = {}
    i = 0
    for mot, phrases in dico2.items():
       i += 1
       if i % 100 == 0: print i
       counts = defaultdict(int)
       dico3[mot] = counts
       for phrase in phrases:
           for autre_mot in dico1[phrase]:
               counts[autre_mot] += 1
    Il tourne en moins de 1min30s (Core 2 Duo 2,4 Ghz), et utilise environ 1,2 GB de RAM. Le traitement n'est pas fini, mais à partir de là tu verras sans doute comment procéder, et le reste ne devrait pas changer l'ordre de grandeur du temps d'exécution il me semble.

  8. #48
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    oui c vrai tu as raison, la valeur de dice sera souvent égale à 0.
    mais j'ai pas compris cet algo:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    for mot, phrases in dico2.items():
       i += 1
       if i % 100 == 0: print i
       counts = defaultdict(int)
       dico3[mot] = counts
       for phrase in phrases:
           for autre_mot in dico1[phrase]:
               counts[autre_mot] += 1
    c'est quoi defaultdict ??
    en fait ce que je n'ai pas compris, c'est counts[autre_mot] += 1
    ,ça correspond à quoi ?

    je peux pas tester le pg, je suis pas devant mon pc perso.
    je le testerai ce soir ton pg

    merci

  9. #49
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    dans ton algo
    je viens de relire ton algo, je ne vois pas trop à quoi il sert dans mon cas.
    car je dois comparer les mots entre eux !

    c'est vrai qu'il serait plus judicieux de ne pas comparer ceux dont la valeur de dice serait égale à 0.pour éviter des calculs inutiles, mais là je ne vois pas trop comment faire à part parcourir ligne par ligne.

  10. #50
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    j'ai compris ton algo !!!
    n'étant pas devant mon pc perso, je peux pas l'éxecuter, donc je l'ai fait tourner à la main
    il est vraiment bien

    pour l'adapter à mon cas notamment avec dice.

    je dois changer

    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    dicevalue = dice(mot,autre_mot)
    etc...
    mais si je fais ça

    je peux comparer plusieurs fois dice (A,C)

    mais en écrivant, je viens de penser, pour éviter de calculer dice (A,C) plusieurs fois, on crée une liste temporaire (listeDéjàTraité) ou on mettrai le mot C dans la liste temporaire

    Et donc avant chaque test de dice, on verifie si "C" est dans la liste temporaire et si oui, on ne recalcule pas dice(A,C).

    cette liste temporaire se viderai à chaque itération de "mot" (de la première boucle)

    je teste ton algo ce soir, je te tiens au courant

    mais un truc, l'algo tu l'a fait tourné sur le fichier mat1.log (60Mo) que j'ai déposé sur mon site ???

    parce que 1min30 c très très rapide!!!!!!!!!!!!!!!!!!!!!!!!!!!

    avec mon premier algo, pendant 16h, il avait meme pas fait 30% du travail!!!
    je sais que mon premier algo était pas génial voir meme pourri mais quand meme 1min30 !!! c du rapide et ça m'arrange en espérant que ce soir, ça fonctionnera aussi rapidement et efficacement

  11. #51
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 418
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 418
    Points : 1 658
    Points
    1 658
    Par défaut
    Je vois que j'ai bien fait de demander d'où est issu le fichier mat1. Ce n'est pas seulement des données exploitables que contiennent les fichiers amont, c'est carrément la solution. En fait, le fichier mat1 représente une perte d'information par rapport à ce qui le précède.

    Mais je suis bête, je n'ai pas saisi l'usage qui pouvait être fait du
    dico1 = { 1:['A','B','C','D','E'], 2:['A','C','D','E'], 3:['B','D','E'] , etc }
    alors que je l'ai examiné un moment pour voir ce qu'on pouvait en tirer !

    J'ai donc écrit un code qui produit le résultat à partir de dico2 seulement.
    Vu que c'est un résultat de comparaison de toutes les lignes entre elles qui t'intéresse véritablement ( puisque tu as un programme de réunification), je suis parti sur cette base: comparer chaque ligne avec ses précedentes et ses suivantes.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    from operator import itemgetter
    from time import clock
     
    m = 20
     
     
    f = open("mat1")
    N = []
    MOTS = []
    PAGES = []
     
    t0 = clock()
    for ln in f:
        a = ln.find('>')
        b = ln.rfind('</')
        N.append(ln.count('##')+1) # count('##')+1 = nombre de pages dans lesquelles le mot de la ligne ln a été trouvé
        MOTS.append(ln[1:a]) # ln[1:a] est le mot de la ligne
        PAGES.append(ln[a+1:b].split('##')) # les éléments de PAGES sont des listes de pages
    f.close()
    nb_mots = len(N)
    print 'Création des 3 listes de base : ',clock() - t0,'  secondes'
     
     
    t0 = clock()
    f1 = open("matricecooccurrenceTest","w")
    dicenn = []
    print '\nProgression temporelle du traitement:'
    print 'top départ :         0   secondes'
    for i in range(nb_mots):  
     
        moti = MOTS[i]
        pagi = PAGES[i]
     
        LL = [ x[1:3] for x in dicenn if x[0]==i ] # x[1:3] est un tuple a deux elements
        # dicenn est une liste de tuples-triplets
        [ dicenn.remove(item) for item in dicenn if item[0]==i ]
     
        SUIV = []
        for j in range(i+1,nb_mots):
            s = N[i] + N[j]
            pages_communes = [ p for p in PAGES[j] if p in pagi ]
            if pages_communes and i!=j:
                valueDice = 2.0*float(len(pages_communes))/float(s)
                SUIV.append((MOTS[j],valueDice))
                dicenn.append((j,moti,valueDice))
     
        LL.extend(SUIV)
        LL.sort(key=itemgetter(1),reverse=True)
        ## LL est une liste de doublets md = (motj,valueDice)
        # [ md[0] for md in LL[-m:] ] est la liste des m co-occurents les plus frequents de moti
     
        f1.writelines('<' + moti + '>' + '##'.join([ md[0] for md in LL[-m:] ]) + '</'+moti+'>\n')
     
        if i%10000 == 0:
            print 'i =',i,' ',clock()-t0,'  secondes'
     
    f1.close()
    Je n'ai pas pensé à utiliser dico1, mais mon code tient compte de 2 choses similaires à celui de dividee:

    - mon code ne calcule valueDice que si les deux mots comparés se trouvent ensemble dans certaines phrases
    pages_communes = [ p for p in PAGES[j] if p in pagi ]
    if pages_communes and i!=j:
    Cas i==j éliminé aussi puisque le dice(i,j) vaut toujours 1.
    Obligé de faire ainsi puisque je n'ai pas pensé que dico1 fournit directement les lignes dans lesquelles se trouvent les co-occurents d'un mot donné.

    - j'ai aussi pensé que le nombre moyen de dices nuls pour un mot donné confronté aux autres doit être très important, sinon cela voudrait dire qu'en moyenne chaque mot aurait beaucoup de co-occurents, ce qui ne pourrait avoir lieu que si les phrases étaient d'autant plus longues que le nombres de dices non nuls serait grand.
    J'ai tiré de cette idée une astuce, compte tenu aussi du fait que la fonction dice est symétrique: dice(i,j) = dice(j,i).
    À mesure qu'on progresse dans l'étude des lignes i, on rencontre en effet de plus en plus de dice(i,j) qui ont déjà été calculés parce qu'ils valent dice(j,i). Compte tenu que les dices non nuls déjà calculés ne sont pas en très grand nombre, il suffit de les enregistrer, au fur et à mesure qu'ils sont calculés, dans une liste dicenn (= dice non nul):
    LL = [ x[1:3] for x in dicenn if x[0]==i ]
    et de les en effacer à mesure qu'il sont plus tard réutilisés:
    [ dicenn.remove(item) for item in dicenn if item[0]==i ]
    En tablant que dicenn garde une taille raisonnable au cours de l'exécution. Car théoriquement sa taille maximale est 980204226, en plus des listes N, M, PAGES que j'utilise.



    Ceci dit, c'est sûr que si la solution se trouve dans dico1, le code de dividee peut être rapide. Je n'ai pas compris avec certitude si le temps de 1mn30 est le temps total pour obtenir le fichier que veut ekremyilmaz, ou s'i c'est une partie seulement du programme.
    J'ai du mal à comprendre le code de dividee, avec ses defaultdict et map mais s'il est rapide, inutile de passer par dico2 effectivement.

  12. #52
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    defaultdict(f) crée un dictionnaire, mais avec la particularité que l'accès à toute clé inexistante cause un appel à la fonction f et retourne la valeur résultante, au lieu de lever une exception (KeyError). Donc defaultdict(int) fait que la fonction int() est appelée lors de l'accès à une clé inexistante. Cette fonction retourne 0. Cela me permet d'écrire:
    sans devoir initialiser counts[autre_mot] à 0. On peut très bien utiliser un dictionnaire normal, mais dans ce cas il faudrait écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if autre_mot not in counts:
        counts[autre_mot] = 0
    counts[autre_mot] += 1
    ou encore:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    counts[autre_mot] = counts.get(autre_mot,0) + 1
    Même chose avec defaultdict(list); les éléments étant ici initialisés à une liste vide.

    Quant à map(int,l[2:-2]), cela permet de convertir la liste de chaînes en une liste d'entiers, pour économiser de la mémoire (sans cela, on utilise quelques centaines de MB de RAM supplémentaires). Cela accélère aussi sans doute un peu le programme, mais de façon moins importante. 'map' applique une fonction (ici: int, qui convertit la chaine en entier) à chaque élément d'une liste, et retourne la liste résultante. map(int,l[2:-2]) est équivalent à la compréhension de liste suivante: [int(x) for x in l[2:-2]].

    Dans mon code, dico3 donne le nombre de co-occurrences de chaque mot avec chaque autre; après on peut calculer la fonction de dice en faisant un parcours de ce dico; il reste ensuite à extraire les 'm' meilleurs résultats pour chaque mot.

    La symétrie dans le calcul des co-occurrences n'est pas exploitée, mais je ne crois pas que cela fera gagner tellement de temps, et cela complique un peu le code.

    Le code qui fait intervenir 'i', c'est seulement pour afficher un état d'avancement pendant l'exécution, vu que je ne savais pas à priori combien de temps cela allait prendre.

  13. #53
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Voici le programme complet, tel que je l'ai compris. Il prend un peu moins de 7 minutes au total sur mon PC. L'utilisation mémoire reste à 1,2 GB. Je n'ai pas compris pourquoi tu parles de filtrer le 'dice' entre 0 et 1, car par construction sa valeur sera toujours entre 0 et 1 (sinon, c'est qu'il y a une erreur dans le code...).

    Il n'y a qu'à adapter le format de sortie.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
     
    from collections import defaultdict
    import re
     
    filename = "c:\\tmp\\mat1.log"
    motif = re.compile(r"</|>|<|#+")
     
    f = file(filename)
    dico2 = {}
    for line in f:
        l = motif.split(line)
        dico2[l[1]] = map(int,l[2:-2])
    f.close()
     
    print "dico2 généré"
     
    dico1 = defaultdict(list)
    for mot, phrases in dico2.iteritems():
        for phrase in phrases:
            dico1[phrase].append(mot)
     
    print "dico1 généré"
     
    # calcul des co-occurences de chaque paire de mots
    dico3 = {}
    i = 0
    for mot, phrases in dico2.items():
       i += 1
       if i % 100 == 0: print i
       counts = defaultdict(int)
       dico3[mot] = counts
       for phrase in phrases:
           for autre_mot in dico1[phrase]:
               if autre_mot <> mot:
                   counts[autre_mot] += 1
     
    del dico1 # plus besoin
     
    # calcul du nombre d'occurences, en écrasant dico2
    for mot in dico2:
        dico2[mot] = len(dico2[mot])
     
    def dice(X,A,B):
        return float(X+X)/(A+B)
     
    # calcul du 'dice' et extractions des 'm' meilleurs résultats:
    outputname = "c:\\tmp\\out.log"
    f = file(outputname, "w")
    m = 20
    for mot1, mots2 in dico3.iteritems():
        # calculer le dice dans la liste l, dont chaque élément est un tuple (dice, mot)
        # Cette structure permet de trier directement la liste résultante
        l = [(dice(X, dico2[mot1], dico2[mot2]), mot2)
             for mot2, X in mots2.iteritems()]
        l.sort(reverse=True)
        # à adapter au format de sortie désiré:
        f.write("%s :\n" % mot1)
        for dice_val, mot2 in l[:m]:
            f.write("\t%s (%.3f)\n" % (mot2, dice_val))
        f.write("\n")
    f.close()
    Le début est identique à mon code précédemment posté, la seule différence est le test (if autre_mot <> mot) pour éviter de compter les co-occurences d'un mot avec lui-même (ce qui donne toujours un dice de 1.0 forcément).
    Ce code n'est pas optimisé, on peut certainement le rendre plus rapide...

  14. #54
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    le filtre 0 à 1, c'est que je ne souhaite pas récupérer les dice == 0 et == 1.
    c'est pour ça.

    j'ai lancé ton pg.

    je vais voir le résultat et je te tiens au courant

  15. #55
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    le programme tourne en moins de 5 min !!!

    maintenant avant de te dire si ça marche ou pas ou si ça donne ce que je veux
    j'aimerai juste que tu m'explique ce bout de code


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    l = [(dice(X, dico2[mot1], dico2[mot2]), mot2)
    for mot2, X in mots2.iteritems()]
    dico2[mot1] et dico[mot2] donne le nombre de cooccurent.

    maintenant j'aimerai savoir c'est quoi X ??

    car j'aimerai filtrer dice, c'est à dire, si X = 1, ne pas le traiter car si X = 1 ça veut dire que le mot apparaisse ensemble qu'une seule fois dans tous le texte.
    et pour mon projet, ça n'a aucun intérêt.

    Bon je ne suis pas obligé de filtrer, mais ça pourrait donner des meilleurs résultats.



    merci

  16. #56
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    ça à l'air de marcher !!!!

    parce que j'avais un petit fichier de test avec 10000 mots.

    j'avais déjà calculé la matrice de cooccurrence (ça m'avait pris beaucoup beaucoup beaucoup de temps)

    et là j'ai vérifié avec ton programme sur ce meme fichier (en 30s ), j'ai les mêmes résultats.

    par contre, il me reste plus que le problème de filtre.

    j'ai ajouté dans ton code un filtre du dice pour ne pas prendre en compte les mots qui apparaisse qu'une seule fois ensemble

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     
    if (X > 1):
                return float(X+X)/(A+B)
            else:
                return -1.0
    puis j'ai rajouté :

    (if mot2 > 0):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
     
    l = [(dice(X, dico2[mot1], dico2[mot2]), mot2)
             for mot2, X in mots2.iteritems() if mot2 > 0]
    mais dans le fichier texte, j'obtiens encore les valeurs qui ont comme valeur de dice == -1

    et j'ai su que ton algo fonctionne quand j'ai comparé mon fichier de matrice de cooccurrence avec celui de out.log

    j'ai par ex pour ton fichier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    Radiacontrôle :
    	Drôme (0.667)
    	société (0.075)
    	être (0.002)
    	élément (-1.000)
    	zone industrielle (-1.000)
    	ville (-1.000)
    	terrain (-1.000)
    	tau|taux (-1.000)
    	souhaiter (-1.000)
    	site nucléaire (-1.000)
    	site (-1.000)
    	révélation (-1.000)
    	réhabiliter (-1.000)
    	retirer (-1.000)
    	radioactivité (-1.000)
    	quitter (-1.000)
    	président (-1.000)
    	préfet (-1.000)
    	proximité (-1.000)
    	produit (-1.000)
    pour mon fichier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <Radiacontrôle>Drôme##société##être</Radiacontrôle>
    si on enlève tous les dice == -1.000 (c'est à dire qu'il apparaissent qu'une seule fois, et donc inutile), on obtiens ma liste.

    donc ton algo déchire et en moins de 4 minutes en plus

    donc si tu as une idée de comment filtrer cela.

    car je me suis renseigné sur ta liste, c'est une liste compréhension!

    dans un post précédent, tu disais on peut faire plus rapide, je t'assure que là, c'est hyper hyper hyper rapide !!!!!!

    en plus, la symétrie est géré, c'est à dire
    que par ex
    si le mot A possède un cooccurent B alors B possède un cooccurent A
    merci encore

  17. #57
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    c'est bon, ça marche !!!

    j'ai rajouté if X > 1 pour enlever tous les mots qui apparaissent une seule fois ensemble dans tous le corpus.

    mais comme l'algo est assez rapide, je peux le mettre en variable pour comparer les résultats à la fin de mon projet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
     
    l = [(dice(X, dico2[mot1], dico2[mot2]), mot2)
             for mot2, X in mots2.iteritems() if X > 1]

    merci pour tous les gars !!!!!!!!!!
    franchement, j'aurai jamais cru qu'on aurait pu m'aider à créer la matrice de cooccurrence, étant donné que c'était pas facile à comprendre et à expliquer pour moi.

    je vous en remercie énormement !!!!!!! et particulièrement à eyquem et dividee

    je vais continuer mon projet, en espérant que ça coincera plus !!!!!!!!

    merci encore les gars

  18. #58
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    juste une dernière chose,
    vu que vous êtes des chaud en python (moi c mon premier projet en python )


    dividee pour le fichier de sortie tu as écrit ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    for dice_val, mot2 in l[:m]:
        f.write("\t%s (%.3f)\n" % (mot2, dice_val))
    moi mon fichier de sortie ressemble à ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    <rivalité/>avoir##être<rivalité/>
    pour cela, j'ai fait ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    for k in range(len(l[:m])):
            if k != len(l[:m]) - 1:
                f.write(str(l[:m][k][1])+"##")
            else:
                f.write(str(l[:m][k][1]))
    ça me permet d'avoir ça :

    <rivalité/>avoir##être<rivalité/>

    et non

    <rivalité/>avoir##être#<rivalité/>

    je sais pas s'il est possible de le faire en une ligne

  19. #59
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    (if mot2 > 0) n'a pas de sens; mot2 est une chaîne de caractères; Python évaluera toujours la condition à True.
    X, dans la compréhension de liste, est ce qu'on a calculé dans dico3; c'est à dire le nombre de cooccurences de mot1 et mot2.

    Avec cet algorithme, le dice ne sera jamais égal à 0 car dans dico3 ne se retrouvent que les mots qui ont au moins une cooccurence.
    Si tu veux exclure les mots qui ont une seule cooccurrence, au lieu du test que tu fais dans la fonction 'dice', tu peux le faire dans la compréhension de liste:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    l = [(dice(X, dico2[mot1], dico2[mot2]), mot2)
             for mot2, X in mots2.iteritems() if X > 1]
    Mais il est plus efficace de les enlever dans dico3 dès qu'on les génère; cela permet d'économiser de la mémoire et d'accélérer la suite du traitement:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # calcul des co-occurences de chaque paire de mots
    dico3 = {}
    i = 0
    for mot, phrases in dico2.items():
       i += 1
       if i % 100 == 0: print i
       counts = defaultdict(int)
       dico3[mot] = counts
       for phrase in phrases:
           for autre_mot in dico1[phrase]:
               if autre_mot <> mot:
                   counts[autre_mot] += 1
       for autre_mot in counts.keys():
           if counts[autre_mot] == 1:
               del counts[autre_mot]
    En testant cela, l'utilisation mémoire n'est pas améliorée (sans doute à cause du garbage collector; mais c'est certainement possible avec une implémentation plus soignée), mais le gain de temps est appréciable: 3 minutes au lieu de 7.

    Si tu veux vraiment filtrer sur la valeur de dice en plus de cela, tu peux le faire après la génération de la liste l:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    l = [(dice(X, dico2[mot1], dico2[mot2]), mot2)
             for mot2, X in mots2.iteritems()]
    l = [(dice_val, mot) for dice_val, mot in l if dice_val < 1.0]
    Mais je ne sais pas si c'est vraiment pertinent, si on a déjà éliminé les co-occurrences uniques...
    en plus, la symétrie est géré, c'est à dire
    que par ex
    si le mot A possède un cooccurent B alors B possède un cooccurent A
    La symétrie est gérée, mais n'est pas exploitée pour accélérer les calculs. C'est une optimisation potentielle.

    Pour la sortie tu peux faire ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        if l:
            f.write("<%s>%s</%s>\n" % (mot1, "##".join(zip(*l[:m])[1]), mot1))
        else:
            f.write("<%s></%s>\n" % (mot1, mot1))
    La partie "else" n'est nécessaire que si tu veux inclure les mots qui n'ont pas de cooccurrences significatives (par exemple: <Naudet></Naudet>)

    "##".join(list) crée une chaîne qui est une concaténation des chaînes dans la liste, séparées par ##.
    zip(*list) peut être décrit comme une transposition de matrice; par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    >>> l = [(0.2,"mot1"),(0.15,"mot2"),(0.1,"mot3")]
    >>> zip(*l)
    [(0.2, 0.15, 0.1), ('mot1', 'mot2', 'mot3')]
    >>> #et donc:
    >>> zip(*l)[1]
    ('mot1', 'mot2', 'mot3')
    >>> "##".join(zip(*l)[1])
    'mot1##mot2##mot3'

  20. #60
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    358
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 358
    Points : 117
    Points
    117
    Par défaut
    je te remercie, de toute manière, le filtrage qu'il soit avant ou après, ça change pas grand chose pour le résultat, 3 ou 7 min c pareil.
    je te le redit, mon algo était parti pour la base de 10J donc 3 ou 7 min c rien.


    par contre, j'ai appris plein de chose sur python et sur la manière de coder en python.

    ça m'a permis d'accélérer un autre algo qui utilise cette matrice de cooccurrence


    par contre,
    j'aimerai juste savoir une chose

    j'ai un fichier de test fourni de cette forme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Aberdeen	Top
    Abidjan	Top
    Abitibi	Top
     
    Entre les deux mots sur la même ligne, il y a un séparateur '\t'
    j'ai utilisé le même principe de dividee pour découper un fichier.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    filename = "learning_lexicon.m2"
    motif = re.compile(r"\t")
    f = file(filename)
    dico = {}
    for ligne in f:
       mot = motif.split(ligne)
       dico[mot[0]] = mot[1]
    return dico
    à la fin je me retrouve avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    dico = { 'Aberdeen:'Top\n', 'Abidjan':'Top\n', 'Abitibi':'Top\n' }
    '

    y-a til un moyen de supprimer le '\n ?
    merci

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. importer fichier long
    Par mizou00 dans le forum Macros et VBA Excel
    Réponses: 15
    Dernier message: 13/08/2010, 08h15
  2. Impossible de transferer des fichiers long
    Par feldene dans le forum Langage
    Réponses: 4
    Dernier message: 24/03/2010, 17h38
  3. Copier les fichiers long Win98/ME
    Par compdev dans le forum Windows 2000/Me/98/95
    Réponses: 1
    Dernier message: 11/09/2009, 21h50
  4. nom de fichier long
    Par karim_usthb dans le forum Scripts/Batch
    Réponses: 0
    Dernier message: 02/06/2008, 11h50
  5. [Win XP] Optimisation (fichier de "swap" et RAM)
    Par BiM dans le forum Windows XP
    Réponses: 11
    Dernier message: 05/04/2006, 12h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo