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

Langage Perl Discussion :

lecture d'un fichier ligne par ligne


Sujet :

Langage Perl

  1. #1
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Janvier 2017
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 32
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 29
    Points : 23
    Points
    23
    Par défaut lecture d'un fichier ligne par ligne
    Bonjour à tous,

    J'ai deux fichier que je veux les lire lignes par ligne, ( le premier contenant un mot par ligne et le deuxième une phrase par ligne) , donc je veux pour chaque mot du premier fichier calculer le nombre des phrases de deuxième fichier contenant ce mot,
    voilà mon code :
    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
     
    #calcul le IDF d'un mot
     
        use strict;
        use warnings;
        use autodie;
        use utf8;
     
     
    my $nbre_ligne = 4159480;
     
    open(my $CorpusMots, '<:utf8', '/home/lenovo/Bureau/MesTravaux/IDF/test') or die "Unable to open for read: $!";
    open(my $CorpusPhrases, '<:utf8', '/home/lenovo/Bureau/MesTravaux/IDF/phrases') or die "Unable to open for read: $!";
    open my $fh_resultat, ">:utf8", '/home/lenovo/Bureau/MesTravaux/IDF/result';
     
     
     
     
     
    my $word;
    while(defined(  $word =  <$CorpusMots> )) {
    chomp $word ;
    $word =~ s/^\s*|\s*$//g;
    my $nb_phrase = 0;
    my $idf;
    my $ph;
    while (defined ( $ph = <$CorpusPhrases> ))
    {
    my @tab = split(/ /, $ph);
    chomp @tab ;
    foreach my $val(@tab) {
     if($word eq $val) 
    {
    $nb_phrase = $nb_phrase + 1;
    last;
    }
    }
    }
    #calcul log 
    if ($nb_phrase == 0) 
    {
    $idf =0;
    }
    else
    {
    $idf = (log(3/$nb_phrase))/log(10);
    }
     
    print $fh_resultat "$word:$idf\n";
    }
    Le code semble bien mais le résultat est faux, en fait l'exécution se fait seulement pour le premier mot du fichier , pourquoi ??

  2. #2
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2017
    Messages
    25
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2017
    Messages : 25
    Points : 11
    Points
    11
    Par défaut
    Je trouve assez pénible de lire un code non-indenté, ça passe sur celui-ci qui est plutôt simple et court, mais pour du code un peu plus compliqué, essaie d'indenter stp.
    Ceci-dit, j'ai l'impression que tu te compliques énormément.
    Dans ta 2nde boucle (celle qui est à l'intérieur de la première) essaie plutôt d'utiliser une expression régulière toute bête qui comptera le nombre d'occurences, et à chaque résultat qu'elle trouve, augmente ton compteur du nombre d'occurrences trouvées.
    En tentant de gérer les occurrences multiples sur une ligne, tu te fais des nœuds au cerveau pour quelque chose qui ne m'a pas l'air si difficile (je peux me tromper).

  3. #3
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    Bonsoir,

    Merci d'apprendre à indenter proprement vos codes pour une meilleure lisibilité :

    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
    #!/usr/bin/perl 
     
    #calcul le IDF d'un mot
     
    use strict;
    use warnings;
    use autodie;
    use utf8;
     
    my $nbre_ligne = 4159480;
     
    open( my $CorpusMots,    '<:utf8', '/home/lenovo/Bureau/MesTravaux/IDF/test' )    or die "Unable to open for read: $!";
    open( my $CorpusPhrases, '<:utf8', '/home/lenovo/Bureau/MesTravaux/IDF/phrases' ) or die "Unable to open for read: $!";
    open my $fh_resultat, ">:utf8", '/home/lenovo/Bureau/MesTravaux/IDF/result';
     
    my $word;
    while ( defined( $word = <$CorpusMots> ) ) {
    	chomp $word;
    	$word =~ s/^\s*|\s*$//g;
    	my $nb_phrase = 0;
    	my $idf;
    	my $ph;
    	while ( defined( $ph = <$CorpusPhrases> ) ) {
    		my @tab = split( / /, $ph );
    		chomp @tab;
    		foreach my $val (@tab) {
    			if ( $word eq $val ) {
    				$nb_phrase = $nb_phrase + 1;
    				last;
    			}
    		}
    	}
     
    	#calcul log
    	if ( $nb_phrase == 0 ) {
    		$idf = 0;
    	}
    	else {
    		$idf = ( log( 3 / $nb_phrase ) ) / log(10);
    	}
     
    	print $fh_resultat "$word:$idf\n";
    }

  4. #4
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par djibril Voir le message
    Bonsoir,

    Merci d'apprendre à indenter proprement vos codes pour une meilleure lisibilité :
    ++.

  5. #5
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Bonjour Ftina,

    il est très inefficace de lire ton deuxième fichier (phrases) autant de fois qu'il y a de mots dans le premier fichier. Sauf si tes fichiers sont énormes, il faut charger l'un d'eux en mémoire (tableau ou hachage), puis lire l'autre une seule fois en le comparant à chacun des éléments que tu as stocké en mémoire.

    Si tu veux pour chaque mot le nombre de phrases où il apparaît (si j'ai bien compris), le plus simple est sans doute de mettre tes mots dans un hachage qui te servira de compteur.

    Un truc dans ce genre (pas testé car il n'y a pas d'exemple de données):
    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
     
    open ... # x3 -> ouverture des trois fichiers
     
    my %words;   # hachage de compteurs
     
    while (my $word = <$CorpusMots> ) {
        chomp $word;
        $words{$word} = 0;
    }
    close $CorpusMots;
     
    while (my $phrase = <$CorpusPhrases>) {
        for my $word (keys %words) {
            $words{$word}++ if index ($phrase, $word) >= 0;  # fonction index bien plus rapide qu'une comparaison individuelle à chaque mot de la phrase (ou même qu'une regex)
        }
    }
    close $CorpusPhrases;
     
    # relire le hash de compteurs et imprimer le résultat dans le fichier de sortie
    for my $word (keys %words) {
        print $fh_resultat "Le mot $word apparaît dans %words{$word} phrases.\n"; # (phrase d'exemple  à remplacer par ton calcul de logarithme)
    }

  6. #6
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Janvier 2017
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 32
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 29
    Points : 23
    Points
    23
    Par défaut
    Citation Envoyé par Lolo78 Voir le message
    Bonjour Ftina,

    il est très inefficace de lire ton deuxième fichier (phrases) autant de fois qu'il y a de mots dans le premier fichier. Sauf si tes fichiers sont énormes, il faut charger l'un d'eux en mémoire (tableau ou hachage), puis lire l'autre une seule fois en le comparant à chacun des éléments que tu as stocké en mémoire.

    Si tu veux pour chaque mot le nombre de phrases où il apparaît (si j'ai bien compris), le plus simple est sans doute de mettre tes mots dans un hachage qui te servira de compteur.

    Un truc dans ce genre (pas testé car il n'y a pas d'exemple de données):
    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
     
    open ... # x3 -> ouverture des trois fichiers
     
    my %words;   # hachage de compteurs
     
    while (my $word = <$CorpusMots> ) {
        chomp $word;
        $words{$word} = 0;
    }
    close $CorpusMots;
     
    while (my $phrase = <$CorpusPhrases>) {
        for my $word (keys %words) {
            $words{$word}++ if index ($phrase, $word) >= 0;  # fonction index bien plus rapide qu'une comparaison individuelle à chaque mot de la phrase (ou même qu'une regex)
        }
    }
    close $CorpusPhrases;
     
    # relire le hash de compteurs et imprimer le résultat dans le fichier de sortie
    for my $word (keys %words) {
        print $fh_resultat "Le mot $word apparaît dans %words{$word} phrases.\n"; # (phrase d'exemple  à remplacer par ton calcul de logarithme)
    }
    Bonsoir LOLO et merci beaucoup pour votre réponse,

    vous voulez dire quoi par : Sauf si tes fichiers sont énormes, il faut charger l'un d'eux en mémoire (tableau ou hachage), puis lire l'autre une seule fois en le comparant à chacun des éléments que tu as stocké en mémoire. (est ce que cettesolution est efficace pour les fichiers de grande taille ? )
    Merci beaucoup de me répondre

  7. #7
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Bonjour Ftina,

    dans la solution type simplifiée que j'ai proposée, le corpus de mots est chargé en mémoire (dans un hachage). Si ce fichier est vraiment très très gros (par exemple des millions ou des dizaines de millions de lignes, selon la mémoire disponible), il ne sera peut-être simplement pas possible de le charger en mémoire, il faudra trouver une autre solution.

    Mais j'imagine que s'agissant d'un corpus de mots, il a tout au plus quelques dizaines de milliers de lignes, voire quelques centaines de milliers. Dans ce cas, aucun problème de taille mémoire, ça passe largement sur les ordinateurs actuels.

    Et pas de problème de performances non plus, le temps d'accès à un élément d'un hachage ne dépend pas de la taille du hachage.

  8. #8
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Janvier 2017
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 32
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 29
    Points : 23
    Points
    23
    Par défaut
    oui il s'agit de plus d'un million des mots pour le corpus des mots, et plus que 4 millions des phrases, mais dès ajourd'hui matin le programme tourne sans résultat, j'ai modifié un peut le code
    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
     
    #calcul le IDF d'un mot
     
        use strict;
        use warnings;
        use autodie;
     
     
    open my $fh_resultat, ">:utf8", '/home/lenovo/Bureau/MesTravaux/IDF/out';
    use constant CORPUS_MOT => '/home/lenovo/Bureau/MesTravaux/IDF/corpus_mots';
    use constant CORPUS_Phrases => '/home/lenovo/Bureau/MesTravaux/IDF/CorpusApprentissage.txt';
     
    open my $fh2, "<:utf8", CORPUS_Phrases;
     
    open my $fh1, "<:utf8", CORPUS_MOT;
     
     
    my %words;   # hachage de compteurs
     
    while (my $word = <$fh1> ) {
        chomp $word;
    next if $word =~ /^\s*$/; 
        $words{$word} = 0;
    }
    close $fh1;
     
    my $nbre_ligne=0;
     
    while (my $phrase = <$fh2>) {
    next if $phrase =~ /^\s*$/; 
    $nbre_ligne++;
        for my $word (keys %words) {
            $words{$word}++ if index ($phrase, $word) >= 0;  
        }
    }
    close $fh2;
    print  $nbre_ligne;
    # relire le hash de compteurs et imprimer le résultat dans le fichier de sortie
    for my $word (keys %words) {
    my $idf;
    if($words{$word} == 0) {$idf =0;} 
     
    else
    {
    $idf = (log($nbre_ligne/$words{$word}))/log(10);
    }
        print $fh_resultat " $word: $words{$word}:$idf\n"; # (phrase d'exemple  à remplacer par ton calcul de logarithme)
    }
    est ce que on peu optimiser encore ?

  9. #9
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Bonjour,
    quand tu dis "tourne sans résultat", veux-tu dire qu'il est très très long et semble ne jamais se terminer, ou veux-tu dire qu'il se termine mais n'écrit ien dans le fichier de sortie?

    Il faudrait que tu essaies le programme avec par exemple un corpus de 20 mots et de 10 phrases (avec certains au moins des mots dans tes phrases) pour vérifier que le programme fonctionne. Inutile de perdre du temps à tester avec de très gros volumes de données si le programme ne marche pas.

    Mais avec un corpus de mots d'un million d'entrées, ça va prendre très longtemps.

    Voici une optimisation possible. Remplacer:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
       for my $word (keys %words) {
            $words{$word}++ if index ($phrase, $word) >= 0;  
        }
    par:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    my @mots_phrase = split / /, $phrase;
    for my $mot (@mots_phrase) {
        $words{$mot}++ if exists $words{$mot}
    }
    La petite difficulté est qu'ici je splitte uniquement sur des espaces; selon le style de tes phrases, il faut peut-être "nettoyer" les signes de ponctuations des mots de @mots_phrase avant de faire la recherche dans le hachage.

    Mais ça devrait aller nettement plus vite.

  10. #10
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Janvier 2017
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 32
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 29
    Points : 23
    Points
    23
    Par défaut
    Bonjour LOLO,
    Le programme avec 20 phrases et 10 mots (la première version) tourne très bien et se termine en qqes secondes, si je le teste sur mes corpus (plus de 4 million des phrases et plus de 1 million du mots), il tourne mais sans rien afficher dans le fichier résultat .. donc combien dois je attendre à votre avis ? et si ça prend énormement du temps y'a t'il pas une autre solution ( diviser les fichiers par exemple ) ?

    avec cette version (en utilisant le split) , le programme ne prend pas en considération les mots se trouvant à la fin d'une ligne (càd si le mots se trouve à la fin de la ligne il n'est pas calculé) , pourquoi selon vous. (mon corpus est toujours nettoyé)

  11. #11
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Ah, oui, probablement parce que le dernier mot a un retour à la ligne attaché, du coup il n'est pas reconnu dans le hachage.

    Essaie ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    chomp $phrase;
    my @mots_phrase = split / /, $phrase;
    for my $mot (@mots_phrase) {
        $words{$mot}++ if exists $words{$mot}
    }
    Ce serait plus facile de t'aider si tu fournissais un petit échantillon de tes données (les deux fichiers en entrée).

  12. #12
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Janvier 2017
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 32
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 29
    Points : 23
    Points
    23
    Par défaut
    Bonsoir, le corpus des phrases sont des lignes de genre:
    يا قوم لا تامنوا ان كنتم غيرا على نسائكم كسرى وما جمعا كالاقحوان استمرت قوم
    هو الجلاء الذي يجتث اصلكم فمن راى مثل ذا رايا ومن سمعا قوم
    فقلدوا امركم لله دركم السفينة رحب الذراع بامر الحرب مضطلعا قوم
    لا مشرفا ان رخاء العيش ساعده ولا اذا عض مكروه به خشعا
    مسهد النوم تعنيه ثغوركم يروم منها الى الاعداء مطلعا
    ما انفك يحلب در الدهر اشطره يكون متبعا طورا ومتبعا
    وليس يشغله مال يثمره عنكم ولا ولد يبغي له الرفعا
    le corpus des mots: (un mot par ligne)
    قوم
    النوم
    ذرعا
    الرياض
    كالاقحوان
    الدهر
    العلم
    استمرت
    يثمره
    السفينة

    ça marche pour le mot se trouvant à la fin, mais reste un autre problème
    il faut tenir compte que de la première occurrence du mot dans une phrase (càd si le mot occurre 2 fois dans une phrase on ne calcule que 1 comme nbre-mot dans cette phrase

  13. #13
    Membre chevronné Avatar de dmganges
    Homme Profil pro
    Retraité. Ne recherche pas un emploi.
    Inscrit en
    Septembre 2011
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Retraité. Ne recherche pas un emploi.
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2011
    Messages : 1 392
    Points : 2 044
    Points
    2 044
    Par défaut
    Bonjour,
    je ne sais pas si c'est la meilleure façon d'opérer mais tu peux supprimer les doublons du tableau des mots de la phrase :

    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
    while (my $phrase = <$fh_Phrases>) {
    	next if $phrase =~ /^\s*$/; 
    	$nbre_ligne++;
    	chomp $phrase;
    	my @mots_phrase = split / /, $phrase;
    	@mots_phrase = doublons_grep( \@mots_phrase );
    	for my $mot (@mots_phrase) {
    		$words{$mot}++ if exists $words{$mot}
    	}
    }
    close $fh_Phrases;
    print  $nbre_ligne;
     
    # relire le hash de compteurs et imprimer le résultat dans le fichier de sortie
    foreach ( sort {$a cmp $b } (keys %words) ) {
    	if ( length( $_ ) > 1 ) {
    		print $fh_Resultat $words{$_} ." - ". $_ ."\n";
    	}
    }
    close $fh_Resultat;
     
     
    #######################################
    # Elimination des doublons d'un tableau
    sub doublons_grep {
      my ($ref_tabeau) = @_;
      my %hash_sans_doublon;
      return grep { !$hash_sans_doublon{$_}++ } @{$ref_tabeau};
    }
    Sur fichier ~ 6200 lignes et ~18300 mots : < 1s.

  14. #14
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Bonjour Ftina,

    si j'ai bien compris: si un mot apparaît deux fois dans une phrase, tu veux ne le compter une seule fois (autrement dit, tu désires compter le nombre de phrases ayant le mot, non le nombre totale d'occurrences du mot).

    Dans ce cas, il faut sans doute dédoublonner la phrase avant de compter les mots.

    Dmganges a donné une solution possible avec une fonction séparée. Une autre solution est d'utiliser un hachage au lieu d'un tableau pour splitter chaque phrase en mots, car un hachage élimine naturellement les doublons. Par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    chomp $phrase;
    my %mots_phrase = map { $_ => 1 } split / /, $phrase;   # élimine les mots en doublon de chaque phrase
    for my $mot (keys %mots_phrase) {
        $words{$mot}++ if exists $words{$mot}
    }

  15. #15
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Janvier 2017
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 32
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 29
    Points : 23
    Points
    23
    Par défaut
    Bonsoir,
    Merci LOLO merci Michel, même avec les optimisations je me trouve toujours avec le problème de out of memory!!

  16. #16
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Alors, tu as un vrai problème, parce que toute solution autre qu'un hachage (par exemple une base de données) sera considérablement plus lente.

    Première solution: trouver un ordinateur plus puissant (si ce n'est pas un traitement répétitif, trouver un ordi plus puissant pour une période limitée de temps n'est pas du tout insurmontable, on peut solliciter une université ou louer des VM sur Internet pour quelques jours ou quelques semaines pour un montant modique) ou acquérir de la mémoire supplémentaire (ce n'est plus très cher de nos jours).

    Deuxième solution: essaie de diviser ton corpus de mots en deux lots de tailles approximativement égales et vois si ça passe en lançant deux fois le traitement, une fois avec chaque lot (éventuellement en parallèle sur deux ordinateurs pour réduire la durée totale d'exécution). Je ne connais pas ton matériel, mais, à mon avis, avec un million de mots, tu es sans doute dans la zone grise entre ce qui passe et ce qui ne passe pas. Avec deux lots de 500.000 mots, il y a de grosses chances que ça marche. Sinon, fais quatre lots de 250.000 mots, et là, ça devrait vraiment aller si ton ordinateur n'est pas une antiquité antédiluvienne sous-dimensionnée.

  17. #17
    Membre chevronné Avatar de dmganges
    Homme Profil pro
    Retraité. Ne recherche pas un emploi.
    Inscrit en
    Septembre 2011
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Retraité. Ne recherche pas un emploi.
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2011
    Messages : 1 392
    Points : 2 044
    Points
    2 044
    Par défaut
    Bonjour,
    Pareil que Lolo78, j'opte pour l'ajout de mémoire par chère.
    La base de données serait le pire, sauf si tu n'avais besoin que de connaître à un instant donné le nombre d’occurrences d'un mot, et ce sur une longue période de temps...
    Construire une base de données pour y faire uniquement un traitement par lot est une aberration.

    Mais si j'interviens c'est parce que je suis étonné du nombre d'entrées dans ton corpus de mot.
    1 million de mots c'est énorme.
    Pour info.
    Tu traites seulement du texte arabe ? ou multilangue, auquel cas ça se comprendrait...
    Comment obtiens-tu le corpus de mots ?
    Si c'est un simple hachage de toutes les lignes de fichiers possibles en entrée, n'y a-t-il pas moyen de le simplifier en amont en supprimant les mots "vides" ?
    - articles, conjonctions, adverbes, remplacer les verbes conjugués par l'infinitif... en français
    - suppression des diacritiques en arabe, la forme trilétère suffit-elle ? ou bien la forme complète est-elle indispensable ?

    Bref, si tu nous exposais un peu la situation, sans entrer dans les détails si c'est confidentiel...
    ça pourrait nous donner d'autres idées...

  18. #18
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Comme Dmgange, un corpus d'un million de mots me paraît énorme. Une langue ordinaire contient environ 50000 mots (y compris les termes scientifiques et littéraires peu comuns et les noms propres courants, etc.). J'ai utilisé pour mes tutoriels des listes de mots pour les jeux de mots croisés et autre jeux de lettres de 120.000 mots, y compris les conjugaisons et les formes féminines ou plurielles, j'ai du mal à comprendre comment tu arrives à un million de mots.

    Une autre question: as-tu vraiment besoin d'un corpus de mots en entrée? Ne peux-tu pas construire ta liste de mots à la volée au fur et à mesure que tu lis tes phrases? Il est pratiquement sûr que de cette façon tu ne trouveras que quelques milliers ou au plus que quelques dizaines de milliers de mots.

    Ceci me fais penser à une autre solution. Même si tu as besoin de cette liste de mots en entrée, tu pourrais construire dynamiquement l'histogramme des mots présents dans les phrases et tu pourrais ensuite filtrer ton corpus de mots avec le hachage des mots trouvés. Si tu ne comprends pas mon idée, demande, je repasserai un peu plus tard et pourrai te fournir un squelette de programme.

  19. #19
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Bonjour Ftina,

    voici ma solution évitant de charger le corpus de mots en mémoire :
    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
     
    open ... # x3 -> ouverture des trois fichiers
     
    my %words;   # hachage de compteurs
     
     
    while (my $phrase = <$CorpusPhrases>) {
        chomp $phrase;
        my %mots_phrase = map { $_ => 1 } split / /, $phrase; 
        for my $mot (keys %mots_phrase) {
            $words{$mot}++;
        }
    }
    close $CorpusPhrases;
     
    while (my $word = <$CorpusMots> ) {
        chomp $word;
        print $fh_resultat "Le mot $word apparaît dans $words{$word} phrases.\n" if exists $words{$word};
    }
    close $CorpusMots;
    close $fh_resultat;
    Le hachage %words ne contient plus le corpus du mots et son million de mots, mais les mots effectivement trouvés dans les phrases, très certainement un nombre d'entrées bien plus faible. Ensuite, le corpus des mots est lu ligne par ligne et non plus chargé en mémoire. Ceci devrait normalement résoudre le problème.

  20. #20
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Janvier 2017
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 32
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2017
    Messages : 29
    Points : 23
    Points
    23
    Par défaut
    Bonjour ,
    Merci pour vos réponses, oui il s'agit de plus qu'un million des mots sans doublons, peut etre je dois éliminer les mots vides .. merci LOLO pour la nouvelle proposition .. les mots sont en arabes..

Discussions similaires

  1. Réponses: 9
    Dernier message: 03/07/2014, 18h08
  2. lire fichier .txt (NOTEPAD) ligne par ligne
    Par skambram dans le forum VB.NET
    Réponses: 1
    Dernier message: 06/06/2009, 18h41
  3. lire un fichier de string ligne par ligne
    Par bilzzbenzbilz dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 11/02/2009, 10h44
  4. [lecture d'un fichier] ligne par ligne
    Par pitit777 dans le forum C++
    Réponses: 3
    Dernier message: 26/11/2005, 11h22
  5. [debutant]lecture fichier ligne par ligne
    Par Battosaiii dans le forum C
    Réponses: 2
    Dernier message: 13/11/2005, 19h02

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