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

SAS Base Discussion :

Evaluation d'une formule contenue dans une variable (Cas soumis par mp )


Sujet :

SAS Base

  1. #1
    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 Evaluation d'une formule contenue dans une variable (Cas soumis par mp )
    Bonjour,

    j'ai été sollicité hier soir par MP au sujet d'un problème d'évaluation de fonction contenue dans un champ texte ci-joint le message anonymisé

    bonjour,
    [...]j'ai un problème concernant l'utilisation des formules dans une table sas, en effet ma table possède 186000 observation,
    je souhaite calculer 5 nouveaux champs, sauf que la formule que je vais utiliser est stocké déjà dans une autre champs comme variable caractère.
    exemple:

    champ1:
    sum(kdc,kve) sachant que dkc est un champ, kve est un champ, et le champ que je veux calculer par exemple est égale a cette formule,
    remarque: la formule change dans la table d'une ligne à une autre.

    je vous remercie par avance
    J'ai proposé une solution (je ne l'ai fait que pour un champ mais ça se généralise facilement à partir de là ), en passant par de la construction de code en "dur" (via la fabrication d'un .sas contenant une macro).

    Je serais curieux de savoir quelles auraient été les autres solutions possibles (sachant qu'attention le fichier est gros donc exit la génération de code spécifique a chaque observation avec du macro 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
    options mprint;
    data b;
    a=1;b=1;champ1="sum(a,b)";output;
    a=1;b=1;champ1="sin(a)";output;
    a=1;b=1;champ1="a-b*b";output;
    a=1;b=1;champ1="sin(a)";output;
    run;
     
     
    filename prog 'z:\autoprog.sas' ;
     
     
    data _null_ ;
    length champ1 $200 ;
    file prog;
    PUT '%MACRO code ;' ;
    PUT 'select(Champ1);' ;
    if _n_=1 then do;
                declare hash champ(dataset:'work.b');
                champ.defineKey('champ1');
                champ.defineDone();
    declare hiter iChamp('champ');
    rc = iChamp.first();
    do while (rc=0);
    VAR ='WHEN("'!!STRIP(Champ1)!!'") Champ1_valeur='!!STRIP(Champ1)!!';' ;
    PUT VAR ;
    rc = iChamp.next();
     
    end; 
    PUT 'OTHERWISE;' ;
    PUT 'END;' ;
    PUT '%MEND;' ;
    end;
    RUN; 
     
    %include "z:\autoprog.sas";
    DATA c; set b;
    %code;
    run;

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    83
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 83
    Points : 137
    Points
    137
    Par défaut
    Attention les yeux c'est très moche

    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
    DATA b;
    a=1;b=1;champ1="sum(a,b)";output;
    a=1;b=1;champ1="sin(a)";output;
    a=1;b=1;champ1="a-b*b";output;
    a=1;b=1;champ1="sin(a)";output;
    run;
     
    data result;
    	length res 8;
    	set _null_;
    	run;
     
    data _null_;
    	set b;
    	call execute(cat("proc sql; insert into result set  res=(select ",champ1," as resultat from b where monotonic()=",_n_,");quit;"));
     
    run;

  3. #3
    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
    Salut,

    il m'expliquait qu'il avait essayé solution macro et call execute et que ça lui prenait une dizaine d'heure en temps de calcul...

    J'ai testé ton code sur 4000 observations, ça dépote quand même bien , un peu moins d'une minute en temps de calcul c'est fait en moins d'une heure pour ces 168 000 observations !
    Sympa ton code.

    Bon celle que je propose est plus bourrine mais reste nettement plus rapide (<1 seconde) sur 4 000.

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Juin 2011
    Messages
    83
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 83
    Points : 137
    Points
    137
    Par défaut
    oui j'avais lu ton message trop rapidement et je me suis rendu compte du pb de perf après coup

    sinon si la perf est vraiment ce qu'on cherche, il y a peut être moyen d'écrire un parseur d'expression en C et d'utiliser la proc proto ensuite pour l'utiliser depuis un data step

  5. #5
    Membre régulier
    Profil pro
    Consultant en Business Intelligence
    Inscrit en
    Septembre 2013
    Messages
    27
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Consultant en Business Intelligence

    Informations forums :
    Inscription : Septembre 2013
    Messages : 27
    Points : 76
    Points
    76
    Par défaut
    Une autre solution (via des macro variables et un resolve) :
    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
    DATA b;
    	format champ1 $15.;
    	do i=1 to 10000;
    		vala=i;valb=mod(i,50);champ1="sum(vala,valb)";output;
    	end;
    run;
     
    data b2;
    	set b;
    	call symput(compress("var"||_n_),tranwrd(tranwrd(champ1,"vala",compress(vala)),"valb",compress(valb)));
    	call symput("nbmax",_N_);
    	obs=_N_;
    run;
     
    %macro test1();
    	data result;
    		format result 15.2;
    		%do i=1 %to &nbmax.;
    			result=resolve(&&&var&i.);
    			obs=&i.;
    			output;
    		%end;
    	run;
    %mend test1;
    %test1;
     
    data end;
    	merge b2 result;
    	by obs;
    run;
    Sur une plus forte volumetrie, il serait préférable de décomposer (par paquet de x lignes) la construction de la table result pour gagner en temps de traitement.

  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 Emrall,

    comme je l'avais dit "exit la génération de code spécifique a chaque observation avec du macro code" car cela génère un code dont le temps d'exécution est de l'ordre de n^2 (les deux codes précédents sont en seulement A.n avec A plus ou moins grands ).
    Si tu regarde ton code pour 10 000 chez moi avec ton code ça met 8 secondes, et ça passe à 68 secondes pour 20 000 observations...
    Alors oui bien sur on peut éclater en petites tables et ça ira plus vite ( 2 (n/2)^2=N^2/2 <N^2).
    C'est une illustration de ce pour quoi le macro code n'est pas fait, bien que le forum "macro" soit, à mon grand dam, remplis d'exemples de résolutions à base de ce type de constructions "contre nature" (si tu permet le terme), qui ne doit se justifier que pour le cas de très petites tables, c'est à dire celle dont la taille est par nature bornée (typiquement des tables de résultats) mais nullement pour réaliser du code de traitement sur des tables de données à taille potentiellement "non bornée".

    Edit : @cscerim3 pour la proc proto je l'ai laissé tombé à jamais (tout du moins tant que je n'aurais pas appris le C est compris de quel C parle la proc proto qui semble laisser un peu circonspect les programmeurs C a qui j'ai pu en parler.... :S )

Discussions similaires

  1. [MySQL-5.1] Etablir un calcul d'une formule contenue dans une colonne
    Par allsys dans le forum Requêtes
    Réponses: 0
    Dernier message: 16/12/2014, 18h35
  2. [WebI XiR2] Exécution d'une formule contenu dans une valeur de champs
    Par Sckizo dans le forum Débuter
    Réponses: 9
    Dernier message: 22/04/2011, 10h57
  3. Réponses: 3
    Dernier message: 07/04/2011, 14h38
  4. Réponses: 0
    Dernier message: 07/06/2009, 12h31
  5. Changer un caractère dans une chaîne contenue dans une phrase
    Par cirtey dans le forum Algorithmes et structures de données
    Réponses: 9
    Dernier message: 07/03/2007, 16h16

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