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

Macro Discussion :

Itérations et sortir d'une boucle


Sujet :

Macro

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut Itérations et sortir d'une boucle
    Bonjour,

    J'ai un problème dont une partie a déjà été abordé mais je n'ai pas réussi à mettre en application les réponses proposés par jerome_pdv2 notamment http://www.developpez.net/forums/d13...ucle-do-while/

    Pour mieux comprendre je vais partir d'un exemple et non de mes réelles données.
    Je dispose de 2 table sas :
    • Une noté tab_base avec une colonne individu et une colonne age

    • Et une 2ème noté tab_opt avec les options que je souhaite vérifier dans la table base (Je souhaite vérifier que l'option sur l'âge correspond à au moins 2 individus).



    1. Je fais une boucle sur le _n_, le problème est qu'il supprime des individus et donc il passe à _n_ =2 alors que l'option à _n_ = 1 n'a pas été vérifié (décalage)

    1. Étant donné que je souhaite que mon programme supprime des lignes dont l'option ne correspond pas à au moins 2 individus, il n’atteint pas la dernière ligne et produit donc une erreur.


    J'ai crée un programme résumant mon exemple.

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    data tab_base;
    input id age;
    cards;
    1 30
    2 31
    3 32
    4 32
    5 33
    ;
    run;
     
     
    data tab_opt;
    input option $ age;
    cards;
    age=30 30
    age=31 31
    age=32 32
    age=33 33
    age=34 34
    age=36 36
    age=37 37
    ;
    run;
     
    %macro abc;
     
    	data _null_;
    		set tab_opt;
    		call symputx('eof',put(_n_,8.),'G');
    	run;
     
    	%put &eof;
     
    	%do i=1 %to &eof.;
    		data _null_;
    			set tab_opt;
    			if _n_ eq &i. then do;
    				call symput(compress("opt&i."),option);	
    			end;
    		run;
     
    		%put &&opt&i;
     
    		proc sql;
    			create TABLE X_SQL as
    			select count(id) as nb
    			from tab_base
    			where &&opt&i.;
    		quit;
     
    		%let N1=0;
     
    		data _null_;
    			set X_SQL;
    			call symput("N1",nb);
    		run;
     
    		%put &N1;
     
    		%if &N1 lt 2 %then %do;
    			data tab_opt;
    				set tab_opt;
    				where not (&&opt&i.);
    			run;
    		%end;
     
    		data _null_;
    			set tab_opt;
    			call symputx('eof',put(_n_,8.),'G');
    		run;
     
    		%put &eof;
     
    	%end; * to eof;
     
    %mend abc;
    %abc;
    Tab_opt donne:
    option age
    age=31 31
    age=32 32
    age=37 37

    Par rapport à mon premier problème je n'aurai pas du garder dans cette table les lignes "age=31 31" et "age=37 37".
    Et concernant mon deuxième problème, ma log me donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    WARNING: Apparent symbolic reference OPT7 not resolved.
    ERROR: Syntax error while parsing WHERE clause.
    Car ma table a été réduite depuis.

    Merci par avance.

    Bien cordialement,

    Alex

  2. #2
    Membre éprouvé
    Avatar de m.brahim
    Homme Profil pro
    SAS / BIG DATA
    Inscrit en
    Juillet 2011
    Messages
    461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : SAS / BIG DATA
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2011
    Messages : 461
    Points : 1 119
    Points
    1 119
    Billets dans le blog
    14
    Par défaut
    Bonjour,

    Étant donné que je souhaite que mon programme supprime des lignes dont l'option ne correspond pas à au moins 2 individus,

    Je te propose cette solution

    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
     
    data tab_base;
    input id age;
    cards;
    1 30
    2 31
    3 32
    4 32
    5 33
    ;
    run;
     
     
    data tab_opt;
    input option $ age;
    cards;
    age=30 30
    age=31 31
    age=32 32
    age=33 33
    age=34 34
    age=36 36
    age=37 37
    ;
    run;
     
    Data tab_base1 (drop=tmp);
    set tab_base;
    by age;
    if first.age then tmp=0;
    tmp+1;
    if tmp>=2;
    run;
     
    data tab_opt(drop=id);
    merge tab_base1(in=a) tab_opt (in=b);
    by age;
    if  a and b;
    run;
    Cordialement
    Certification des Talents de la programmation In Memory Statistics sur HADOOP:
    http://talents-imstat.groupe-avisia....avance?uid=162

  3. #3
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut
    Merci m.brahim pour ta réponse mais comme je disais ceci est un exemple. Ta réponse ne convient pas pour mes réelles données car mes options sont beaucoup plus compliqué que ça je dois forcément les extraire de leurs bases (tab_opt) pour ensuite vérifier leur n correspondant dans tab_base.

  4. #4
    Membre éprouvé
    Avatar de m.brahim
    Homme Profil pro
    SAS / BIG DATA
    Inscrit en
    Juillet 2011
    Messages
    461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : SAS / BIG DATA
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2011
    Messages : 461
    Points : 1 119
    Points
    1 119
    Billets dans le blog
    14
    Par défaut
    Bonjour,

    ne convient pas pour mes réelles données
    Quelles types de différences peut ils exister?

    Cordialement
    Certification des Talents de la programmation In Memory Statistics sur HADOOP:
    http://talents-imstat.groupe-avisia....avance?uid=162

  5. #5
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    data tab_opt;
    length option $ 200;
    input nvar option $;
    cards;
    3 (age_ge_20_and_age_le_60)
    3 (age_ge_22_and_age_lt_42)
    3 (imc_ge_24_and_imc_lt_28)
    3 (poids_ge_63_and_poids_lt_127)
    2 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)
    1 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)_(poids_ge_63_and_poids_lt_127)
    ;
    run;
    NB : Il faut remplacer les "_" par les espaces. Je n'ai pas su sur le coup comment créer un dataset avec cards contenant des espaces dans les variables caractères.

  6. #6
    Membre expérimenté
    Homme Profil pro
    Attaché statisticien
    Inscrit en
    Mai 2011
    Messages
    687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Attaché statisticien
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2011
    Messages : 687
    Points : 1 581
    Points
    1 581
    Par défaut
    Bonjour,

    j'essaye de reformuler car que je n'arrive pas à voir le lien de ton problème avec le topic cité, et puis c'est peut-être aussi lundi matin, pas trop réveillé .

    Tu as une table A avec des individus et des caractéristiques.
    Tu as une table B avec des ""options"" qui sont autant de test sur les caractéristiques de tes individus dans A.

    Tu souhaite ne conserver dans A que les individus de A qui remplissent une condition de B, à la condition qu'ils ne soient pas seuls dans la table A à remplir cette condition (au moins 2...) ?

    Ou encore dit autrement : Tu souhaite sélectionner les ""options"" de B remplies par au moins deux individus de A (=>B prime), et ne conserver de A que les individus remplissant au moins l'une des conditions identifiées de B ( (=>cad appartenant à B prime).

    Est-ce cela ?

  7. #7
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut
    Salut jerome_pdv2,

    C'est presque cela, mis à part que je ne modifie pas la table A contenant les individus et caractéristiques mais je que je veux conserver dans ma table B contenant les "options" seulement celles qui remplissent la condition dans la table A.

    Concernant le liens avec le topic cité, c'est que je souhaite également sortir de ma boucle à un instant donné car sinon je rencontre des erreurs.

  8. #8
    Membre expérimenté
    Homme Profil pro
    Attaché statisticien
    Inscrit en
    Mai 2011
    Messages
    687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Attaché statisticien
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2011
    Messages : 687
    Points : 1 581
    Points
    1 581
    Par défaut
    et nvar dans tab_opt correspond à quoi ?

  9. #9
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut
    si nvar=1 : il y a 3 variables différentes dans l'option
    si nvar=2 : il y a 2 variables différentes dans l'option
    si nvar=3 : il y a 1 variable dans l'option

    Je l'ai mise car je l'ai, mais on est pas forcé de l'utiliser.

  10. #10
    Membre expérimenté
    Homme Profil pro
    Attaché statisticien
    Inscrit en
    Mai 2011
    Messages
    687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Attaché statisticien
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2011
    Messages : 687
    Points : 1 581
    Points
    1 581
    Par défaut
    Tu complique les choses....

    Bon déjà si toutes les variables sont présentes (j'ai rajouté les variables qui manquaient).

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
     
    data tab_opt;
    length option $ 200;
    input nvar option $;
    cards;
    3 (age_ge_20_and_age_le_60)
    3 (age_ge_22_and_age_lt_42)
    3 (imc_ge_24_and_imc_lt_28)
    3 (poids_ge_63_and_poids_lt_127)
    2 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)
    1 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)_and_(poids_ge_63_and_poids_lt_127)
    ;
    run;
     
    data tab_base;
    input id age imc poids;
    cards;
    1 30 25.3 80
    2 31 28.3 95
    3 32 19.6 53
    4 32 31 105
    5 33 22 85
    ;
     
     
    data tab_opt;set tab_opt;
    option=translate(option," ","_"); /*** remplace les _ par des blancs **/
    run;
     
     
     
    /*** début programme **/
     
     
       /*** on place les options dans des macro variables (ID1,ID2 etc...) et on calcul le nombre d options nboption **/
    DATA _null_;
    SET tab_opt END=eof;
    call symput (cats('ID',put(_n_,best.)),option);
    IF eof THEN call symput ("nboption",_n_);
    run;
     
     
     
    %MACRO m;
    DATA _null_;
    LENGTH Somme 8. Option $200.  ;
     
    IF _N_=1 THEN 	DO; /** definition de la statistique de comptage **/
    				DECLARE HASH COMPTE() ;
    				COMPTE.DefineKey("Option");
    				COMPTE.DefineData("Option","Somme");
    				COMPTE.DefineDone();
    				END;
     
    SET Tab_Base END=eof; /** on charge les individus **/
     
    %DO I =1 %TO &nboption; /** on boucle sur toutes les options **/
    Test=&&ID&I;/** on évalue l option pour chaque individu **/
     
    /** puis mise à jour de la statistique de comptage , seules les options valides au moins une fois auront une statistique de comptage **/
    IF Test=1 THEN 	DO;Option="&&ID&I";RC=COMPTE.FIND();IF RC=0 THEN DO;Somme++1;RC=COMPTE.REPLACE();END;
    															ELSE DO;Somme=1;RC=COMPTE.ADD();END;
    				END;
    %END;
     
    /** on sort les stattistiques de comptage **/
    IF EOF THEN COMPTE.OUTPUT(dataset:"STAT_OPTION");
    RUN;
     
    %MEND;
     
    %m;
     
    PROC PRINT DATA=STAT_OPTION ;RUN;
     
     
    DATA Selection; SET STAT_OPTION; IF Somme>=2;RUN;
    O
    p S
    t o
    O i m
    b o m
    s n e

    1 (age ge 20 and age le 60) and (imc ge 24 and imc lt 28) 1
    2 (poids ge 63 and poids lt 127) 4
    3 (age ge 20 and age le 60) and (imc ge 24 and imc lt 28) and (poids ge 63 and poids lt 127) 1
    4 (age ge 20 and age le 60) 5
    5 (imc ge 24 and imc lt 28) 1
    6 (age ge 22 and age lt 42) 5

  11. #11
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut
    Ok merci jerome_pdv2. Je vais étudier ça et essayer de le faire correspondre à mes besoins.

    A quel niveau du code je peux modifier pour pouvoir conserver les options valides au moins 3 fois par exemple ?

    Donc finalement avec mon programme que je vous présentais, j'y étais pas du tout ?

  12. #12
    Membre expérimenté
    Homme Profil pro
    Attaché statisticien
    Inscrit en
    Mai 2011
    Messages
    687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Attaché statisticien
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2011
    Messages : 687
    Points : 1 581
    Points
    1 581
    Par défaut
    tout à la fin

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DATA Selection; SET STAT_OPTION; IF Somme>=3;RUN;
    ton code je vois un peu ce que tu voulais faire, après il n'y a pas une seule façon de coder, dans ton approche, tu faisais autant de SQL il me semble que de conditions, ce qui veut dire lire la table des observations autant de fois qu'il y a d'option. Dans mon code on ne lis la table des observations qu'une seule fois.
    Après où ton code cloche ? Je n'ai pas trop d'idées, je ne suis pas allé dans le détail du code.

  13. #13
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut
    Ah ok merci, j'étais pas allé jusqu'à la fin.

    Oui mon approche mettait beaucoup plus de temps en plus.

  14. #14
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut
    C'est tout bon. Merci encore

  15. #15
    Membre expérimenté
    Homme Profil pro
    Développeur en SAS/ Statisticien
    Inscrit en
    Janvier 2013
    Messages
    483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Développeur en SAS/ Statisticien
    Secteur : Enseignement

    Informations forums :
    Inscription : Janvier 2013
    Messages : 483
    Points : 1 552
    Points
    1 552
    Par défaut
    Bonjour,
    C’est une idée, je pense qu’on n’a pas besoin de la table TAB_OPT et les codes se trouvant dans la variable option peuvent être saisis directement dans le programme comme ceci :
    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
     
    data tab_base;
    input id age imc poids;
    cards;
    1 30 25.3 80
    2 31 28.3 95
    3 32 19.6 53
    4 32 31 105
    5 33 22 85
    ;
    run ;   
     
    data Option ;
    set  tab_base ; 
    array Mat{3} age--poids ; 
     
    if(age ge 20 and age le 60)       
    	then do ; Option=1 ; output ;  end ;
    if(age ge 22 and age lt 42)  
    	then do ; Option=2 ; output ;  end ;
    if(imc ge 24 and imc lt 28)  
    	then do ; Option=3 ; output ;  end ;
    if(poids ge 63 and poids lt 127) 
    	then do ; Option=4 ; output ;  end ;
    if(age ge 20 and age le 60) and (imc ge 24 and imc lt 28) 
    	then do ; Option=5 ; output ;  end ;
    if(age ge 20 and age le 60) and (imc ge 24 and imc lt 28) and (poids ge 63 and poids lt 127) 
    	then do ; Option=6 ; output ;  end ;
    run ;			 
     
    proc freq data=Option noprint ;
    tables Option /out=out_Freq(drop=percent where=(count ge 2)) ;
    run ;
    Cdt Ward

  16. #16
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut
    Bonjour,

    Désolé d'ouvrir de nouveau le sujet mais j'aimerais y ajouter une condition qui est de vérifier le nombre d'individu dans 2 groupes.

    Voilà le code de Jerome_pdv2 que j'ai légèrement modifier pour répondre à ça.
    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    data tab_opt;
    length option $ 200;
    input nvar option $;
    cards;
    3 (age_ge_20_and_age_le_60)
    3 (age_ge_22_and_age_lt_42)
    3 (imc_ge_24_and_imc_lt_28)
    3 (poids_ge_63_and_poids_lt_127)
    2 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)
    1 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)_and_(poids_ge_63_and_poids_lt_127)
    ;
    run;
     
    data tab_base;
    input id groupe age imc poids;
    cards;
    1 2 30 25.3 80
    2 1 31 28.3 95
    3 2 32 19.6 53
    4 1 32 31 105
    5 1 33 22 85
    6 1 30 25.3 80
    7 1 31 28.3 95
    8 2 32 19.6 53
    9 1 32 31 105
    10 1 33 22 85
    ;
     
     
    data tab_opt;
    	set tab_opt;
    	option=translate(option," ","_"); /*** remplace les _ par des blancs **/
    run;
     
     
    data _null_;
    	set tab_opt end=eof;
    	call symput (cats('ID',put(_N_,best.)),option);
    	if eof then call symput ("nboption",put(_N_,8.));
    run;
     
    /*** Hash object ***/
    %macro Hash;
    	data _null_;
    	length ngrp1 8. ngrp2 8. Option $200.  ;
     
    	/* definition de la statistique de comptage */
    	if _N_=1 then do; 
    		DECLARE HASH COMPTE() ;
    		COMPTE.DefineKey("Option");
    		COMPTE.DefineData("Option","ngrp1","ngrp2");
    		COMPTE.DefineDone();
    	end;
     
    	do until (eof1);
    		set tab_base (where=(groupe eq 1)) end=eof1; /** on charge les individus **/
    		%do i=1 %to &nboption.; /** on boucle sur toutes les options **/
    			Test=&&ID&i; /** on évalue l option pour chaque individu **/
    			/** puis mise à jour de la statistique de comptage , seules les options valides au moins une fois auront une statistique de comptage **/
    			IF Test=1 then do;
    				Option="&&ID&i";
    				RC=COMPTE.FIND();
    				if RC=0 then do;
    					ngrp1++1;
    					RC=COMPTE.REPLACE();
    				end;
    				else do;
    					ngrp1=1;
    					RC=COMPTE.ADD();
    				end;
    			end;
    		%end;
    	end;
     
    	do until (eof2);
    		set tab_base (where=(groupe eq 2)) end=eof2;
    		%do i=1 %to &nboption.;
    			Test=&&ID&i; 
    			IF Test=1 then do;
    				Option="&&ID&i";
    				RC=COMPTE.FIND();
    				if RC=0 then do;
    					ngrp2++1;
    					RC=COMPTE.REPLACE();
    				end;
    				else do;
    					ngrp2=1;
    					RC=COMPTE.ADD();
    				end;
    			end;
    		%end;
    	end;
     
    	/*** we output counting statistics ***/
    	/** on sort les stattistiques de comptage **/
    	if eof1 then COMPTE.OUTPUT(dataset:"STAT_OPTION");
    	run;
     
    %mend;
     
    %hash;
     
    data SELECTION;
    	set STAT_OPTION;
    	where (ngrp1 gt 2) and (ngrp2 gt 2);
    run;
     
    proc print data=SELECTION;
    run;
    Résultat :
    Obs Option ngrp1 ngrp2
    1 (age ge 20 and age le 60) 7 3
    2 (age ge 22 and age lt 42) 7 3


    Le code fonctionne mais je ne pense pas que ça soit la façon la plus simple et correct de le faire.

    De plus, lorsque j'ai un très grand nombre d'options (200 000 par exemple), j'obtiens une erreur d'insuffisance mémoire tel que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ERROR: The SAS System stopped processing this step because of insufficient memory.
    Auriez-vous une idée pour optimiser le code et/ou corriger cette erreur ?

    Merci beaucoup.

    Aleksik

  17. #17
    Membre expérimenté
    Homme Profil pro
    Attaché statisticien
    Inscrit en
    Mai 2011
    Messages
    687
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Attaché statisticien
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2011
    Messages : 687
    Points : 1 581
    Points
    1 581
    Par défaut
    Bonjour,

    le code adapté à ton nouveau cas (les tests pourraient être optimisés mais bon...)

    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    data tab_opt;
    length option $ 200;
    input nvar option $;
    cards;
    3 (age_ge_20_and_age_le_60)
    3 (age_ge_22_and_age_lt_42)
    3 (imc_ge_24_and_imc_lt_28)
    3 (poids_ge_63_and_poids_lt_127)
    2 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)
    1 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)_and_(poids_ge_63_and_poids_lt_127)
    ;
    run;
     
    data tab_base;
    input id groupe age imc poids;
    cards;
    1 2 30 25.3 80
    2 1 31 28.3 95
    3 2 32 19.6 53
    4 1 32 31 105
    5 1 33 22 85
    6 1 30 25.3 80
    7 1 31 28.3 95
    8 2 32 19.6 53
    9 1 32 31 105
    10 1 33 22 85
    ;
     
     
    data tab_opt;
    	set tab_opt;
    	option=translate(option," ","_"); /*** remplace les _ par des blancs **/
    run;
     
     
    data _null_;
    	set tab_opt end=eof;
    	call symput (cats('ID',put(_N_,best.)),option);
    	if eof then call symput ("nboption",put(_N_,8.));
    run;
     
    /*** Hash object ***/
    %macro Hash;
    	data _null_;
    	length ngrp1 8. ngrp2 8. Option $200.  ;
     
    	/* definition de la statistique de comptage */
    	if _N_=1 then do; 
    		DECLARE HASH COMPTE() ;
    		COMPTE.DefineKey("Option");
    		COMPTE.DefineData("Option","ngrp1","ngrp2");
    		COMPTE.DefineDone();
    	end;
     
    	do until (eof1);
    		set tab_base  end=eof1; /** on charge les individus **/
    		%do i=1 %to &nboption.; /** on boucle sur toutes les options **/
    			Test=&&ID&i; /** on évalue l option pour chaque individu **/
    			/** puis mise à jour de la statistique de comptage , seules les options valides au moins une fois auront une statistique de comptage **/
    			IF Test=1 then do;
    				Option="&&ID&i";
    				RC=COMPTE.FIND();
    				if RC=0 then do;
    					ngrp1=ngrp1+(groupe=1);
    					ngrp2=ngrp2+(groupe=2);
    					RC=COMPTE.REPLACE();
    				end;
    				else do;
    					ngrp1=(groupe=1);ngrp2=(groupe=2);
    					RC=COMPTE.ADD();
    				end;
    			end;
    		%end;
    	end;
     
     
     
    	/*** we output counting statistics ***/
    	/** on sort les stattistiques de comptage **/
    	if eof1 then COMPTE.OUTPUT(dataset:"STAT_OPTION");
    	run;
     
    %mend;
     
    %hash;
     
    data SELECTION;
    	set STAT_OPTION;
    	where (ngrp1 gt 2) and (ngrp2 gt 2);
    run;
     
    proc print data=SELECTION;
    run;
    Quant à l'erreur que tu rencontre, elle est très probablement due à l'utilisation des tableaux associatifs qui sont des objets chargés en mémoire vive (ton objet hash "COMPTE").
    Bien que... une variable texte + 2 variables numériques + clé de hachage, à la louche 300 octets par 200 000 ça fait dans les 60 Mo ce qui n'est pas très élevé, (à 2 000 000 j'aurais mieux compris).

    Je pense que c'est ça et donc si c'est le cas :

    Première option : tu n'as pas assez de mémoire vive, mais tu en as d'inutilisée et tu as la main sur cette options alors tu pourrais voir à régler avec l'options memsize pour t'en allouer davantage et peut-être que ça marchera.

    Deuxième option : ce qui te coûte beaucoup de mémoire (et aussi certainement de temps de calcul ) dans le code ainsi présenté, c'est ton identifiant de test (variable "option") car c'est du caractère sur 200 positions... Et en fait c'est à priori inutile (et en plus ça te coute aussi beaucoup de temps d'écriture en sortie). Tu pourrais utiliser comme identifiant "option" comme ainsi défini option=&I.; en modifiant également la déclaration de type d'option plus haut dans le code. Tu pourra toujours retrouver ton test en faisant la jointure ultérieurement entre ta table de résultats et ta table initiale d'option qui a servi à créer les macro variables d'option.

    Et là tu auras beaucoup plus de place.

    3ème option : Ensuite si tu compte soumettre un nombre considérable d'options, il te faudra saucissoner ta base d'options en sous base de sorte que chacune des sous bases rentrent dans la capacité mémoire de ton ordinateur/serveur.


    Edit : 200 000 options... ça veut dire 200 000 macro variables... des millions de lignes de code générées par la boucle macro... c'est peut-être ici aussi que le bas blesse en fait et dans ce cas ce serait plus simple de passer par l'option 3.
    Peut-être qu'il y aurait d'autre façon de s'organiser en fonction de comment tu construit ta base d'options.

    Edit2 : pour optimiser les temps de calcul lié à la taille de ton tableau associatif il faudrait également utiliser le paramètre hashexp et le fixer à 15 ou 16 hashexp: 16 pour un nombre d'options de l'ordre de 100 000

  18. #18
    Membre éprouvé
    Avatar de m.brahim
    Homme Profil pro
    SAS / BIG DATA
    Inscrit en
    Juillet 2011
    Messages
    461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : SAS / BIG DATA
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2011
    Messages : 461
    Points : 1 119
    Points
    1 119
    Billets dans le blog
    14
    Par défaut
    Bonjour,

    A tester cette solution:


    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
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
     
    data tab_opt;
    length option $ 200;
    input nvar option $;
    cards;
    3 (age_ge_20_and_age_le_60)
    3 (age_ge_10_and_age_le_50)
    3 (age_ge_22_and_age_lt_42)
    3 (imc_ge_24_and_imc_lt_28)
    3 (poids_ge_63_and_poids_lt_127)
    2 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)
    1 (age_ge_20_and_age_le_60)_and_(imc_ge_24_and_imc_lt_28)_and_(poids_ge_63_and_poids_lt_127)
    ;
    run;
     
    data tab_base;
    input id groupe age imc poids;
    cards;
    1 2 30 25.3 80
    2 1 31 28.3 95
    3 2 32 19.6 53
    4 1 32 31 105
    5 1 33 22 85
    6 1 30 25.3 80
    7 1 31 28.3 95
    8 2 32 19.6 53
    9 1 32 31 105
    10 1 33 22 85
    ;
     
     
    data tab_opt;
    	set tab_opt;
    	option=translate(option," ","_"); 
    run;
     
     
    %macro test(option=);
        data test1;
    	length option  $200.;
     
        	set tab_base (where=(groupe eq 1)) ; 
     
    			Test=&option; 
    			if test=1 then do;
    			option="&option";
    	    	output;
    		    end;
     
    	run;
     
    proc append base=test11 data=test1 force ;run;
     
         data test2;
    	 length option  $200.;
    	 set tab_base (where=(groupe eq 2)) ; 
         Test=&option; 
    	 if test=1 then do;
         option="&option";
    	 output;
    	 end;
     
    	run;
     
     proc append base=test22 data=test2 force ;run;
     
    %mend;
     
    DATA _null_;
    SET tab_opt;
     call execute('%nrstr(%test(option='||strip(option)||'));');
    run; 
     
     
    proc sort data=test11; by option ;run;
     
    proc sort data=test22; by option ;run;
     
     
     
    data test11;
    set test11;
    by option;
    retain somme1 ;
           if first.option   then do;
           somme1=1;end;
           else  somme1=somme1+1;
           if last.option then output;
     
    run;
     
    data test22;
    set test22;
    by option;
    retain somme2;
           if first.option   then do;
           somme2=1;end;
           else  somme2=somme2+1;
           if last.option then output;
     
    run;
     
    data resultats(keep=option somme1 somme2);
    merge test11 test22;
    if somme1 >2 and somme2>2;
    run;
     
    proc datasets lib=WORK;
    delete test:;
    run;
    Cordialement
    Certification des Talents de la programmation In Memory Statistics sur HADOOP:
    http://talents-imstat.groupe-avisia....avance?uid=162

  19. #19
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2015
    Messages : 71
    Points : 67
    Points
    67
    Par défaut
    Merci beaucoup Jerome_pdv2 et m.brahim pour vos nouvelles réponses.

    J'ai actuellement utilisé le code de Jérôme en mettant en place l'option 3 que tu me proposais.

    M.brahim, ton code fonctionne et je t'en remercie, mais il est moins efficace en temps de calcul.

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

Discussions similaires

  1. Sortir d'une boucle for
    Par gids01 dans le forum Langage
    Réponses: 9
    Dernier message: 14/11/2006, 15h06
  2. Sortir d'une boucle de parcour d'un Recordset
    Par Mariboo dans le forum IHM
    Réponses: 2
    Dernier message: 12/06/2006, 18h07
  3. Sortir d'une boucle en fonction d'une durée
    Par BECHE dans le forum Langage
    Réponses: 8
    Dernier message: 30/11/2005, 11h08
  4. [DEBUTANT] sortir d'une boucle avec un touche particulière
    Par thibouille dans le forum Débuter
    Réponses: 4
    Dernier message: 25/10/2005, 06h44
  5. SORTIR D'UNE BOUCLE
    Par chekibperl dans le forum Langage
    Réponses: 2
    Dernier message: 22/10/2005, 12h48

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