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 :

hash: marier des individus avec des caractéristiques proches


Sujet :

SAS Base

  1. #1
    Candidat au Club
    Inscrit en
    Juin 2009
    Messages
    7
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 7
    Points : 3
    Points
    3
    Par défaut hash: marier des individus avec des caractéristiques proches
    Bonjour,

    je souhaite marier des femmes avec des hommes en respectant certaines caractéristiques , ici pour simplifier une différence d'age et des groupes proches.
    Exemple, je souhaite mariée une femme de la génération 1960 (génération) et du groupe 2 avec un homme sachant que l'homme doit être marié avec une femme qui est de la génération 1960 (gen_conjointe) et dans le groupe 2 (var gpe_conjointe) .

    Voici les 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
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    data base_f;
      input ind $ generation gpe gen_conjoint gpe_conjoint count;
    datalines;
    1 1960 1 1913 3 0
    2 1960 2 1917 2 0
    3 1960 3 1917 1 0
    4 1960 3 1923 3 0
    5 1960 3 1923 2 0
    6 1960 1 1919 1 0
    7 1960 2 1925 2 0
    8 1960 1 1925 1 0
    9 1960 1 1923 2 0
    10 1960 3 1925 2 0
     
    ;
     
     
    data base_h;
      input ind_cj $ generation_cj gpe_cj gen_conjointe gpe_conjointe;
    datalines;
    1 1913 3 1960 3
    2 1914 2 1960 3
    3 1916 1 1960 1
    4 1917 1 1960 1
    5 1919 1 1960 -1
    6 1921 1 1960 1
    7 1921 1 1960 0
    8 1922 3 1960 3
    9 1922 1 1960 0
    10 1923 2 1960 3
    11 1923 1 1960 0
    12 1923 1 1960 0
    13 1923 1 1960 -1
    14 1923 1 1960 -1
    15 1924 1 1960 -1
    16 1924 1 1960 1
    17 1924 1 1960 0
    18 1925 2 1960 1
    19 1925 1 1960 1
    20 1925 3 1960 3
    ;
    je souhaite associer aux femmes de la base_f des hommes dont la génération de la conjointe =génération (femmes) et gpe conjointe =gpe femmes.
    Idéalement j'ai aussi la condition inverse generation_cj=gen_conjoint et gpe_cj=gpe_conjoint.
    Si je ne retrouve pas le conjoint qui respecte ces clauses strictement je voudrais associer les conjoints les plus proches .
    Voici 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
    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
     
     
    data _null_;
    if _n_=1 then do;
    set base_f(obs=1); 
     
    declare hash cases(dataset:'base_f',hashexp:8,ordered:'y');
    cases.definekey("ind");
    cases.definedata("ind","count","generation", "gpe");
    cases.definedone();
     
    declare hiter hi_cases('cases'); * declare a hash table iterator object;
     
    declare hash matches(); *declare a hash table for matched cases and controls;
    matches.definekey("ind","ind_cj");
    matches.definedata("ind","ind_cj","generation", "gpe","gen_conjointe", "gpe_conjointe");
    matches.definedone();
     
    ind_cj_hash=ind;
     
    declare hash m_control();
    m_control.definekey("ind_cj_hash");
    m_control.definedone();
    m_control.clear();
    end;
     
    set base_h end=eof;
    ind_cj_hash=ind_cj;
     
    if (m_control.find() ne 0) then do; 
    		rc=hi_cases.first(); 
    		do while(rc=0);
    			if (count<1 ) then do; 
    				if generation=gen_conjointe   and gpe=gpe_conjointe  then do;
    					count+1;
    					cases.replace();
    					matches.add();
    					m_control.add();
    					leave;
    				end;
     
    			end;
    			rc=hi_cases.next();
    		end;
    end;
     
    if (m_control.find() ne 0) then do;
    		rc=hi_cases.first();
    		do while(rc=0);
    			if (count<1 ) then do; 
    				if  gpe=gpe_conjointe+1  then do;
    					count+1;
    					cases.replace();
    					matches.add();
    					m_control.add();
    					leave;
    				end;
     
    			end;
    			rc=hi_cases.next();
    		end;
    end;
     
    done=1;
    rc=hi_cases.first();
    do while(rc=0);
    		if count<1 then do;
    		done=0;
    		leave;
    		end;
    rc=hi_cases.next();
    end;
     
    if (done or eof) then do;
    matches.output(dataset:"matches");
    cases.output(dataset:"matched_cases");
    m_control.output(dataset:"matched_controls");
    stop;
    end;
    run;
    Le problème de ce code est qu'il ne faudrait pas que j'ai juste if gpe=gpe_conjointe+1 mais que je boucle pour trouver le plus proche si j'ai pas d'égalité.
    (je n'ai pas encore intégré les autres conditions)
    Aussi selon comment est trié ma table je trouve pas la même chose .
    Exemple ici : je trouve 7 correspondances exactes et 3 proches, si je trie ma table d'une autre façon j'ai plus que 5 correspondances exactes.
    Je voudrais que les individus choisis soient les plus proches possible et pouvoir marier toutes mes femmes.
    Je ne connait pas bien cette technique de hachage, est ce que quelqu'un saurait m'aider?

    Cordialement
    Mathilde

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

    J'ai initié cette requête sql.
    Pourrais m'indiquer, stp, à travers les résultats obtenus, ceux qu'ils sont corrects et ceux qu'ils sont faux ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    proc sql;
    create table mariage as select 
    a.ind as ind_f,  a.generation as generation_f, a.gpe as gpe_f, a.gen_conjoint as gen_conjoint_f, a.gpe_conjoint as gpe_conjoint_f,
    b.ind_cj as ind_cj_h,  b.generation_cj as generation_cj_h, b.gpe_cj as gpe_cj_h, b.gen_conjointe as gen_conjointe_h,
    b.gpe_conjointe as gpe_conjointe_h
    from base_f as a inner join base_h as b
    on a.ind=b.ind_cj
    and a.generation=b.gen_conjointe
     
    ;quit;
    Cordialement
    Certification des Talents de la programmation In Memory Statistics sur HADOOP:
    http://talents-imstat.groupe-avisia....avance?uid=162

  3. #3
    Candidat au Club
    Inscrit en
    Juin 2009
    Messages
    7
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Bonjour,
    désolé pour le délai, j’étais en congé..
    A travers ta requête et la condition unique a.generation=b.gen_conjointe tous les résultats sont corrects. Mais il fallait aussi respecter la condition gpe_cj=gpe_conjoint.
    Dans ce cas les individus femmes 4,5 ,7 ,8 et 9 ne respectent pas la condition et ne sont pas les individus dont l'écart est mininal entre les groupes.
    Dans ton exemple la somme des différences entre les groupes =7 .
    Une réponse optimale est par exemple cette association : cf colonne 4 (ind_cj optimal) où la somme des écarts vaut 2.
    ind_f ind_cj_h
    (associé par brahim)
    Ecart
    (gpe_conjoint_f-gpe_cj_h)
    ind_cj_h
    (optimal)
    Ecarts
    1 1 0 1 0
    2 2 0 2 0
    3 3 0 3 0
    4 4 2 8 0
    5 5 1 10 0
    6 6 0 4 0
    7 7 1 18 0
    8 8 2 5 0
    9 9 1 11 1
    10 10 0 7 1
    Total 7 2

    J'ai modifié mon code comme suit pour essayer d'associer mes individus de manière optimale c'est à dire en minimisant l'écart entre gpe_cj et gpe_conjoint.
    L'idée étant que je récupère le max de personnes avec un écart nul puis si on ne peut pas associer tout le monde on prend ensuite un écart de 1 ...
    J'ai donc créée une boucle comme dans le code ci dessous.
    Le problème est que si je boucle que de 0 à 0 (individus avec un écart nul ) il me trouve bien 8 individus ce qui est correct mais ensuite quand je boucle de 0 à 1 il m'associe tous les individus mais seul 7 individus avec un écart nul et 3 individus avec un écart de 1 hors dans la solution optimale je dois avoir 8 individus avec un écart nul et 2 individus avec un ecart de 1.

    Je rate une sortie de boucle ou quelque chose...
    Vous pouvez m'aider?

    Dans cet exemple l'impact est faible mais sur mes 6 millions d'individus si je boucle jusqu'à 50 il me trouve plus d'individus avec des gros écarts...
    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
     
    data _null_;
    if _n_=1 then do;
    set base_f(obs=1); *make the variables in Cases data set available in the PDV;
     
    *put the cases in a hash table;
    declare hash cases(dataset:'base_f',hashexp:8,ordered:'a');
    cases.definekey("ind");
    cases.definedata("ind","count","generation", "gpe","gpe_conjoint");
    cases.definedone();
     
    declare hiter hi_cases('cases'); * declare a hash table iterator object;
     
    declare hash matches(); *declare a hash table for matched cases and controls;
    matches.definekey("ind","ind_cj");
    matches.definedata("ind","ind_cj","generation", "gpe","gen_conjointe", "gpe_conjointe","gpe_cj","gpe_conjoint");
     
    matches.definedone();
    *declare a hash table for recording matched controls;
    ident_cj_hash=ind;
     
     
     
    declare hash m_control();
    m_control.definekey("ident_cj_hash");
    m_control.definedone();
    m_control.clear();
    end;
     
    set base_h end=eof;
    ident_cj_hash=ind_cj;
     
    do i=0 to 5 ;
     
    if (m_control.find()ne 0) then do;
    		rc=hi_cases.first();
    		do while(rc=0);
    			if (count<1 ) then do; 
    				if  (abs(generation-gen_conjointe)+ abs(gpe_conjoint-gpe_cj))=i  then do;
    					count+1;
    					cases.replace();
    					matches.add();
    					m_control.add();
    					leave;
    				end;
     
    			end;
    			rc=hi_cases.next();
    		end;
    end;
     
    end;
     
    done=1;
    rc=hi_cases.first();
    do while(rc=0);
    		if count<1 then do;
    		done=0;
    		leave;
    		end;
    rc=hi_cases.next();
    end;
    *if all the cases are matched or run out of controls, output the resulting data sets;
    if (done or eof) then do;
    matches.output(dataset:"matches");
    cases.output(dataset:"matched_cases");
    m_control.output(dataset:"matched_controls");
    stop;
    end;
    run;
     
    data matches;
    set matches;
    diff_gpe=abs(gpe_conjoint-gpe_cj);
    run;

  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 Mathilde,
    J'ai modifié les clés de jointure. Est ce que le fait de prendre le minimum des différences pour chaque ind pourrais résoudre le problème?
    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
    proc sql;
    create table mariage as select 
    a.ind as ind_f,a.generation as generation_f, a.gpe as gpe_f, a.gen_conjoint as gen_conjoint_f, a.gpe_conjoint as gpe_conjoint_f,
    b.ind_cj as ind_cj_h,  b.generation_cj as generation_cj_h, b.gpe_cj as gpe_cj_h, b.gen_conjointe as gen_conjointe_h,
    b.gpe_conjointe as gpe_conjointe_h
     
    from base_f as a inner join base_h as b
    on 
    (
    a.generation=b.gen_conjointe and a.gpe_conjoint=b.gpe_cj
    )
    or 
     (
     b.generation_cj=a.gen_conjoint and  b.gpe_cj=a.gpe_conjoint
     )
    ;quit;
    Cordialement
    Certification des Talents de la programmation In Memory Statistics sur HADOOP:
    http://talents-imstat.groupe-avisia....avance?uid=162

  5. #5
    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
    Le problème est que si je boucle que de 0 à 0 (individus avec un écart nul ) il me trouve bien 8 individus ce qui est correct mais ensuite quand je boucle de 0 à 1 il m'associe tous les individus mais seul 7 individus avec un écart nul et 3 individus avec un écart de 1 hors dans la solution optimale je dois avoir 8 individus avec un écart nul et 2 individus avec un ecart de 1.
    La sortie matches correspond au maximum i de la boucle (do i=1 to 5).

    Il me semble que l'erreur provient de cette boucle.
    Pour contourner ce problème, je te propose cette solution, manuelle dans un premier temps.
    A vérifier si les résultats obtenus sont ceux qui sont attendus avant d'envisager son automatisation.

    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
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
     
    data base_f;
      input ind $ generation gpe gen_conjoint gpe_conjoint count;
    datalines;
    1 1960 1 1913 3 0
    2 1960 2 1917 2 0
    3 1960 3 1917 1 0
    4 1960 3 1923 3 0
    5 1960 3 1923 2 0
    6 1960 1 1919 1 0
    7 1960 2 1925 2 0
    8 1960 1 1925 1 0
    9 1960 1 1923 2 0
    10 1960 3 1925 2 0
     
    ;
     
     
    data base_h;
      input ind_cj $ generation_cj gpe_cj gen_conjointe gpe_conjointe;
    datalines;
    1 1913 3 1960 3
    2 1914 2 1960 3
    3 1916 1 1960 1
    4 1917 1 1960 1
    5 1919 1 1960 -1
    6 1921 1 1960 1
    7 1921 1 1960 0
    8 1922 3 1960 3
    9 1922 1 1960 0
    10 1923 2 1960 3
    11 1923 1 1960 0
    12 1923 1 1960 0
    13 1923 1 1960 -1
    14 1923 1 1960 -1
    15 1924 1 1960 -1
    16 1924 1 1960 1
    17 1924 1 1960 0
    18 1925 2 1960 1
    19 1925 1 1960 1
    20 1925 3 1960 3
    ;
     
    data _null_;
    if _n_=1 then do;
    set base_f(obs=1); *make the variables in Cases data set available in the PDV;
     
    *put the cases in a hash table;
    declare hash cases(dataset:'base_f',hashexp:8,ordered:'a');
    cases.definekey("ind");
    cases.definedata("ind","count","generation", "gpe","gpe_conjoint");
    cases.definedone();
     
    declare hiter hi_cases('cases'); * declare a hash table iterator object;
     
    declare hash matches(); *declare a hash table for matched cases and controls;
    matches.definekey("ind","ind_cj");
    matches.definedata("ind","ind_cj","generation", "gpe","gen_conjointe", "gpe_conjointe","gpe_cj","gpe_conjoint");
     
    matches.definedone();
    *declare a hash table for recording matched controls;
    ident_cj_hash=ind;
     
     
     
    declare hash m_control();
    m_control.definekey("ident_cj_hash");
    m_control.definedone();
    m_control.clear();
    end;
     
    set base_h end=eof;
    ident_cj_hash=ind_cj;
     
     
     
    if (m_control.find()ne 0) then do;
    		rc=hi_cases.first();
    		do while(rc=0);
    			if (count<1 ) then do; 
    				if  (abs(generation-gen_conjointe)+ abs(gpe_conjoint-gpe_cj))=0  then do;
    					count+1;
    					cases.replace();
    					matches.add();
    					m_control.add();
    					leave;
    				end;
     
    			end;
    			rc=hi_cases.next();
    		end;
    end;
     
     
    done=1;
    rc=hi_cases.first();
    do while(rc=0);
    		if count<1 then do;
    		done=0;
    		leave;
    		end;
    rc=hi_cases.next();
    end;
    *if all the cases are matched or run out of controls, output the resulting data sets;
    if (done or eof) then do;
    matches.output(dataset:"matches");
    cases.output(dataset:"matched_cases");
    m_control.output(dataset:"matched_controls");
    stop;
    end;
    run;
     
    proc sql;
    create table diff_f as select a.* from base_f as a  left join matches as b
    on a.ind=b.ind
    where  b.ind is null;
    quit;
     
     
    proc sql;
    create table diff_h as select a.* from base_h as a  left join matches as b
    on a.ind_cj=b.ind_cj
    where  b.ind is null;
    quit;
     
     
    data _null_;
    if _n_=1 then do;
    set diff(obs=1); *make the variables in Cases data set available in the PDV;
     
    *put the cases in a hash table;
    declare hash cases(dataset:'diff',hashexp:8,ordered:'a');
    cases.definekey("ind");
    cases.definedata("ind","count","generation", "gpe","gpe_conjoint");
    cases.definedone();
     
    declare hiter hi_cases('cases'); * declare a hash table iterator object;
     
    declare hash matches(); *declare a hash table for matched cases and controls;
    matches.definekey("ind","ind_cj");
    matches.definedata("ind","ind_cj","generation", "gpe","gen_conjointe", "gpe_conjointe","gpe_cj","gpe_conjoint");
     
    matches.definedone();
    *declare a hash table for recording matched controls;
    ident_cj_hash=ind;
     
     
     
    declare hash m_control();
    m_control.definekey("ident_cj_hash");
    m_control.definedone();
    m_control.clear();
    end;
     
    set diff_h end=eof;
    ident_cj_hash=ind_cj;
     
     
     
    if (m_control.find()ne 0) then do;
    		rc=hi_cases.first();
    		do while(rc=0);
    			if (count<1 ) then do; 
    				if  (abs(generation-gen_conjointe)+ abs(gpe_conjoint-gpe_cj))=1  then do;
    					count+1;
    					cases.replace();
    					matches.add();
    					m_control.add();
    					leave;
    				end;
     
    			end;
    			rc=hi_cases.next();
    		end;
    end;
     
     
    done=1;
    rc=hi_cases.first();
    do while(rc=0);
    		if count<1 then do;
    		done=0;
    		leave;
    		end;
    rc=hi_cases.next();
    end;
    *if all the cases are matched or run out of controls, output the resulting data sets;
    if (done or eof) then do;
    matches.output(dataset:"matches1");
    cases.output(dataset:"matched_cases");
    m_control.output(dataset:"matched_controls");
    stop;
    end;
    run;
    Cordialement
    Certification des Talents de la programmation In Memory Statistics sur HADOOP:
    http://talents-imstat.groupe-avisia....avance?uid=162

  6. #6
    Candidat au Club
    Inscrit en
    Juin 2009
    Messages
    7
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 7
    Points : 3
    Points
    3
    Par défaut
    Bonjour,
    en faisant ta solution "manuelle" les résultats correspondent bien à l'attendu enfin la sélection est optimal la somme des écarts vaut 2 .
    Par contre cette solution va être coûteuse en temps à cause des jointures car j'ai 7 millions d'individus dans la base réelle..

    Cordialement
    Mathilde

Discussions similaires

  1. Réponses: 4
    Dernier message: 08/06/2016, 11h53
  2. Trouver des points proches avec un champ contenant une différence
    Par Jean-Marc68 dans le forum Accès aux données
    Réponses: 1
    Dernier message: 07/06/2016, 19h36
  3. Afficher le hash d'une row avec des colonnes binaires
    Par aserf dans le forum Développement
    Réponses: 11
    Dernier message: 28/09/2015, 11h46
  4. Réponses: 2
    Dernier message: 04/08/2005, 12h26
  5. Changer des caractéristique dans la DB
    Par tripper.dim dans le forum SQL
    Réponses: 4
    Dernier message: 04/09/2004, 23h31

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