Précédent   Forum des professionnels en informatique > Logiciels > Solutions d'entreprise > Business Intelligence > SAS > SAS Base
SAS Base Forum d'entraide sur SAS base : étape data, procédures non statistiques, procédures non graphiques, SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 04/07/2011, 16h35   #1
Invité régulier
 
Inscription : septembre 2008
Messages : 46
Détails du profil
Informations forums :
Inscription : septembre 2008
Messages : 46
Points : 9
Points : 9
Par défaut Table multi-ligne par individu

Bonjour,

J'ai plusieurs tables de la forme :
ID VAR1 VAR2
1 d111 d211
1 d112 d212
1 d113 d213
2 d121 d221
2 d122 d222
C'est-à-dire, plusieurs lignes par individu ID.

Je souhaite les transformer de sorte qu'il n'y ait plus qu'un individu ID par ligne:
ID|VAR1_1|VAR1_2|VAR1_3|VAR2_1|VAR2_2|VAR2_3
1-|d111--|d112---|d113--|d211---|d212--|d213--
2-|d121--|d122---|-------|d221---|d222--|-------

J'ai commencé par créer des rangs logiques, pour répartir les données dans les Var1_1, Var1_2, Var1_3, mais les ex-aequo me posent problème.

Ensuite je dois définir le nombre de lignes maximum par ID pour savoir combien d'occurences n je dois avoir par Variable (Var1_1, Var1_2, Var1_3, .... Var1_n)

Je comptais, enfin, répartir pour chaque rang (1,2,3...n) les données dans les variables recréées (Var1_1, Var1_2, Var1_3, .... Var1_n).

Je me demandais d'abord, s'il n'existait pas une fonction (ou un extrait de code) type sur SAS pour ce type de transformation.
Sinon je reste bloquée aux ex-aequo, pour la génération des rangs.

Merci.
viougt est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/07/2011, 16h40   #2
Modérateur
 
Homme Samir SELMANE
Consultant en Business Intelligence
Inscription : février 2011
Messages : 1 006
Détails du profil
Informations personnelles :
Nom : Homme Samir SELMANE
Localisation : France

Informations professionnelles :
Activité : Consultant en Business Intelligence
Secteur : Conseil

Informations forums :
Inscription : février 2011
Messages : 1 006
Points : 1 703
Points : 1 703
ce n'est pas la proc transpose que tu recherches?
s_a_m est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/07/2011, 17h02   #3
Membre Expert
 
Avatar de MEGAMIND2
 
Homme Brice Beare
Paris
Inscription : janvier 2011
Messages : 956
Détails du profil
Informations personnelles :
Nom : Homme Brice Beare
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Paris

Informations forums :
Inscription : janvier 2011
Messages : 956
Points : 1 366
Points : 1 366
Bonjour,
Une solution à ton problème

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
DATA test;
input
ID$ VAR1$ VAR2$;
cards;
1 d111 d211
1 d112 d212
1 d113 d213
2 d121 d221
2 d122 d222
;
run;
 
DATA test2;SET test;keep id var2;RENAME var2=var1;run;
 
DATA test3;SET test;keep id var1;run;
 
DATA test;SET test2 test3;run;
 
proc sort DATA=test;BY id;run;
 
proc transpose DATA=test out=transpose(DROP=_name_) prefix=var;var var1 ;BY id;run;
MEGAMIND2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/07/2011, 17h42   #4
Invité régulier
 
Inscription : septembre 2008
Messages : 46
Détails du profil
Informations forums :
Inscription : septembre 2008
Messages : 46
Points : 9
Points : 9
Désolée, ma mise en page était un peu ratée...

Tout d'abord s_a_m, la PROC TRANSPOSE seule me ferait :
ID---|1---|1----|1---|2----|2
VAR1|d111|d112|d113|d121|d122
VAR2|d211|d212|d213|d221|d222
avec les variables qui basculent en ligne

ce que je veux c'est bien :
ID|VAR1_1|VAR1_2|VAR1_3|VAR2_1|VAR2_2|VAR2_3
1-|d111--|d112---|d113--|d211---|d212--|d213--
2-|d121--|d122---|-------|d221---|d222--|-------
où les informations d'un individu sur 3 lignes sont regroupées sur une seule ligne, mais en 3 variables


Ensuite MEGAMIND2, ce que tu proposes donne :
ID|var1-|var2|var3-|var4|var5|var6
1-|d211|d212|d213|d111|d112|d113
2-|d221|d222|d121|d122|----|-----

Dans mon cas de figure, VAR1 et VAR2 ne sont pas regroupables. Je peux en avoir plusieurs de nature complètement différentes.
Je veux garder la distinction entre Var1_n et Var2_n, et donc leurs répartitions. (cf ID=2)
viougt est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/07/2011, 21h32   #5
Membre Expert
 
Avatar de MEGAMIND2
 
Homme Brice Beare
Paris
Inscription : janvier 2011
Messages : 956
Détails du profil
Informations personnelles :
Nom : Homme Brice Beare
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Paris

Informations forums :
Inscription : janvier 2011
Messages : 956
Points : 1 366
Points : 1 366
C'est pas ce que tu as posté initialement...
MEGAMIND2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/07/2011, 21h34   #6
Membre éclairé
 
Homme
statisticien
Inscription : mai 2011
Messages : 212
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Paris (Île de France)

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

Informations forums :
Inscription : mai 2011
Messages : 212
Points : 319
Points : 319
Bonsoir

Citation:
mais les ex-aequo me posent problème
Quels problèmes te posent-ils ?

Concernant ta question je te propose une solution qui répond à ta question me semble-t-il à l'exception de l'ordre des variables finales...

Code :
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
DATA test;
input
ID$ VAR1$ VAR2$;
cards;
1 d111 d211
1 d112 d212
1 d113 d213
2 d121 d221
2 d122 d222
3 d131 d231
3 d132 d232
3 d133 d233
4 d141 d241
4 d142 d242
;
run;
 
 
DATA test;
SET test;
retain rang -1 id_ref 'X';
IF _N_=1 then do;rang=1;id_ref=id;end;
else IF id_ref=id then rang+1;else do;rang=1;id_ref=id;end;
DROP id_ref;
run;
 
 
proc transpose DATA=test out=test;
BY id rang;
var var1 var2;
run;
 
DATA test; SET test;var=compress(_name_!!'_'!!rang);
 
proc transpose DATA=test out=test;
BY id;
var col1; id var;
run;
 
DATA test; SET test; DROP _name_;run;
cela donne

Code :
1
2
3
4
5
6
7
8
 
 
              Obs    ID    VAR1_1    VAR2_1    VAR1_2    VAR2_2    VAR1_3    VAR2_3
 
               1     1      d111      d211      d112      d212      d113      d213
               2     2      d121      d221      d122      d222
               3     3      d131      d231      d132      d232      d133      d233
               4     4      d141      d241      d142      d242

Mais.... il y a sans doute (peut-être ?) plus simple.
jerome_pdv2 est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 04/07/2011, 21h49   #7
Membre Expert
 
Avatar de MEGAMIND2
 
Homme Brice Beare
Paris
Inscription : janvier 2011
Messages : 956
Détails du profil
Informations personnelles :
Nom : Homme Brice Beare
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Paris

Informations forums :
Inscription : janvier 2011
Messages : 956
Points : 1 366
Points : 1 366
Beau gosse Jerome
MEGAMIND2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/07/2011, 07h11   #8
Expert Confirmé
 
Avatar de olivier.decourt
 
Homme Olivier Decourt
Formateur en informatique
Inscription : avril 2008
Messages : 1 467
Détails du profil
Informations personnelles :
Nom : Homme Olivier Decourt
Âge : 34
Localisation : France

Informations professionnelles :
Activité : Formateur en informatique
Secteur : Conseil

Informations forums :
Inscription : avril 2008
Messages : 1 467
Points : 2 823
Points : 2 823
Pas sûr qu'il y ait plus simple que ta solution Jérôme.
S'il y a à la fois des variables numériques et d'autres de type caractère, il faudra les traiter séparément.
Je propose
Code :
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
DATA test;
input
ID$ VAR1$ VAR2;
cards;
1 d111 211
1 d112 212
1 d113 213
2 d121 221
2 d122 222
;
run;
DATA work.pour_transpose_num ;
  SET test ;
  BY id ;
  ARRAY varNum var2 ; /* <-- énumérer toutes les variables numériques */
  IF FIRST.id THEN cpt=0 ;
  cpt+1 ; /* compteur de n° de répétition par id */
  DO OVER varNum ;
     valeur = varNum ;
	 nom = CATX("_",VNAME(varNum),cpt) ;
	 OUTPUT ;
  END ;
RUN ;
DATA work.pour_transpose_car ;
  SET test ;
  BY id ;
  ARRAY varCar $ var1 ; /* <-- énumérer toutes les variables caractère */
  IF FIRST.id THEN cpt=0 ;
  cpt+1 ; /* compteur de n° de répétition par id */
  DO OVER varCar ;
     valeur = varCar ;
	 nom = CATX("_",VNAME(varCar),cpt) ;
	 OUTPUT ;
  END ;
RUN ;
PROC TRANSPOSE DATA=work.pour_transpose_num OUT=work.num (DROP=_name_) ;
  BY id ;
  VAR valeur ;
  ID nom ;
RUN ;
PROC TRANSPOSE DATA=work.pour_transpose_car OUT=work.car (DROP=_name_) ;
  BY id ;
  VAR valeur ;
  ID nom ;
RUN ;
DATA work.fin ;
  MERGE work.num work.car ;
  BY id ;
RUN ;
Le tout étant, comme le montrait Jérôme, de bien préparer les noms des futures colonnes avant de transposer.
olivier.decourt est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 05/07/2011, 14h51   #9
Invité régulier
 
Inscription : septembre 2008
Messages : 46
Détails du profil
Informations forums :
Inscription : septembre 2008
Messages : 46
Points : 9
Points : 9
Merci olivier.decourt ça me convient tout à fait.

Il va juste falloir que je me familiarise plus aux ARRAY et aux différentes formes de TRANSPOSE, pour en faire autant une prochaine fois !

J'ai ajouté un tri en fonction des variables clés, avant d'appliquer le compteur.

Pour finir, auriez-vous une astuce pour remettre les variables dans le même ordre qu'à l'origine ? (avant les indices _1, _2, _3... et la séparation Num/Car)
viougt est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/07/2011, 15h07   #10
Membre Expert
 
Avatar de MEGAMIND2
 
Homme Brice Beare
Paris
Inscription : janvier 2011
Messages : 956
Détails du profil
Informations personnelles :
Nom : Homme Brice Beare
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Paris

Informations forums :
Inscription : janvier 2011
Messages : 956
Points : 1 366
Points : 1 366
Tu peux dire MERCI à Jérome aussi.
Voici comment tu peux ordonner tes variables (les attribs fait le même boulot)

data table2;
retain var1 var2 ...;
set table;
run;
MEGAMIND2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/07/2011, 15h21   #11
Invité régulier
 
Inscription : septembre 2008
Messages : 46
Détails du profil
Informations forums :
Inscription : septembre 2008
Messages : 46
Points : 9
Points : 9
Biensûr : merci jerome_pdv2.
C'est une logique de programmation intéressante aussi.

Sinon y a-t-il moyen de récupérer l'ordre des variables directement à partir de la table d'origine, sans entrer manuellement toutes les variables à la fin ?
Je complique toujours les choses, mais c'est que ce soit réutilisable pour différentes tables.
viougt est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/07/2011, 15h34   #12
Membre Expert
 
Avatar de MEGAMIND2
 
Homme Brice Beare
Paris
Inscription : janvier 2011
Messages : 956
Détails du profil
Informations personnelles :
Nom : Homme Brice Beare
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Paris

Informations forums :
Inscription : janvier 2011
Messages : 956
Points : 1 366
Points : 1 366
Il faut passer pas une proc contents pour récuperer le nom de tes variables dans la table initiale, les stockés dans une macro liste puis l'appeler au moment opportun.
Adaptes ceci à ton cas:


proc contents data=sashelp.class out=out;
run;

proc sort data=out;
by varnum;
run;

proc sql;
select name into: liste separated by " " from out;
quit;
%put liste=&liste.;


data table2;
retain &liste.;
set sashelp.class;
run;


Désolé, les balises code ne marchent pas
MEGAMIND2 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/07/2011, 17h18   #13
Invité régulier
 
Inscription : septembre 2008
Messages : 46
Détails du profil
Informations forums :
Inscription : septembre 2008
Messages : 46
Points : 9
Points : 9
Merci MEGAMIND2.

Je vous transmet donc mon programme final :

Code :
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 test;
input
ID$ VAR1$ VAR2$ VAR3;
cards;
10 d111 d211 311
10 d112 d212 312
10 d113 d213 313
20 d121 d221 321
20 d122 d222 322
30 d131 d231 331
30 d132 d232 332
30 d133 d233 333
40 d141 d241 341
40 d142 d242 342
;
run;

/* récup ordre variables */
proc contents data=test out=ctnt noprint;
run;

proc sort data=test;
by id var1 _all_; /* Tri en fonction des variables prioritaires */
run;
data test;
set test;
  BY id ;
  IF FIRST.id THEN cpt=0 ;
  cpt+1 ; /* compteur de n° de répétition par id */
run;
%macro type(x,y,z);
DATA work.&x ;
  SET test ;
  BY id ;
  ARRAY &x &y ; 
  DO OVER &x ;
  	if upcase(VNAME(&x)) notin('ID','OBS','CPT') then do;
     valeur = &x ;
	 nom = CATX("_",VNAME(&x),cpt) ;
	 OUTPUT ;
	end;  
  END ;
RUN ;

PROC TRANSPOSE DATA=work.&x OUT=work.&z (DROP=_name_) ;
  BY id ;
  VAR valeur ;
  ID nom ;
RUN ;
%mend;
%type(varnum,_numeric_,num);
%type(varCar,_character_,car);

DATA work.test2 ;
  MERGE work.num work.car ;
  BY id ;
RUN ;

proc contents data=test2 out=ctnt2 noprint;
run;

proc sql;
create table ctnt3 as
select ctnt.name as n1, ctnt.varnum as v1, ctnt2.name as n2, ctnt2.varnum as v2
from ctnt left join ctnt2 on ctnt.name=scan(ctnt2.name,1,'_')
order by ctnt.varnum, ctnt2.varnum;
quit;

proc sql;
select n2 into: liste separated by " " from ctnt3;
quit;
%put liste=&liste.;

data test3;
retain &liste.;
set test2;
run;
viougt est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/07/2011, 17h48   #14
Modérateur
 
Homme Samir SELMANE
Consultant en Business Intelligence
Inscription : février 2011
Messages : 1 006
Détails du profil
Informations personnelles :
Nom : Homme Samir SELMANE
Localisation : France

Informations professionnelles :
Activité : Consultant en Business Intelligence
Secteur : Conseil

Informations forums :
Inscription : février 2011
Messages : 1 006
Points : 1 703
Points : 1 703
autre méthode pour revenir au premier ordre des variables:
ici je crée la table test pour modifier l'ordre des variables de la table Sashelp.class ensuite je crée une table var_classe avec des variables de même ordre que la Sashalp.class;
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
 
 
DATA test;
retain weight height age name sex;
SET sashelp.class;
run;
 
proc sql;
 
SELECT name INTO : vari separated BY ',' FROM dictionary.COLUMNS WHERE upcase (libname)= 'SASHELP' AND upcase (memname)='CLASS';
 
CREATE TABLE var_classe AS SELECT &vari  FROM test
 
;
quit;
s_a_m est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 23h18.


 
 
 
 
Partenaires

Hébergement Web