1. #1
    Nouveau Candidat au Club
    Inscrit en
    juin 2009
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : juin 2009
    Messages : 3
    Points : 1
    Points
    1

    Par défaut Selection couples d'individus puis suppression individus déjà pris

    Bonjour,

    Ma problématique consiste à associer les individus deux à deux tels qu'ils soient les plus proches c'est à dire que ma variable "cout" soit minimale sachant qu'un individus ne peut être sélectionné 2 fois.
    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
     
    data have;
      input ind1 $ ind2 $ cout;
    datalines;
    1 A 2
    1 B 5 
    1 C 3
    2 A 1
    2 B 10 
    2 C 5
    3 A 5
    3 B 4 
    3 C 55
    ;
    Je calcule un cout minimum par ind1:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    proc sort data=have; by ind1 cout;run;
    proc summary data=have;var cout;by ind1;output out=min_ind1(drop=_FREQ_ _TYPE_) min=min_cout;run;
     
    data have;merge have min_ind1;by ind1;run;
     
    proc sort data=have; by descending min_cout;run;
     
    /*ensuite je calcule un compteur par ind1 et cout min*/
    data have; 
    set have;
    retain cpt;
    if _N_=1 then cpt=0;
    if ind1 ne lag(ind1) then  cpt=cpt+1;
    run ;
    Et je voudrais avoir en sortie une table qui contient:
    1 A 2
    3 B 4
    2 C 5

    Je ne vois pas comment faire à part faire de multiples data set qui balaye la table sachant que ma "vraie" table contient des milliers d'individus:

    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
     
    %macro test();
    data reste;set have;run;
     
    data out;set _null_;run;
     
    %do i=1 %to 3; /*nombre d'individus 1*/
     
    proc sort data=reste; by cpt;run;
     
    data reste out_1; 	
    set reste;
    by cpt;
    if first.cpt and cpt=&i. then output out_1;
    if cpt=&i. then delete;output reste;
    run;
     
    data out; set out out_1;run;
     
    proc sort data=reste; by  ind2;run; 
    proc sort data=out; by  ind2;run;
     
    data reste; 
    merge reste(in=a) out(in=b);
    by  ind2;
    if a and not b;
    run;
    %end;
     
    %mend;
    %test;
    Avez vous une idée pour optimiser ce programme?
    Cordialement
    Mathilde

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

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

    Informations forums :
    Inscription : mai 2011
    Messages : 672
    Points : 1 557
    Points
    1 557

    Par défaut

    Bonjour, l'optimisation est aisée, mais que se passe t il lorsque deux ind2 ont un même coût , lequel choisi t on ?

  3. #3
    Nouveau Candidat au Club
    Inscrit en
    juin 2009
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : juin 2009
    Messages : 3
    Points : 1
    Points
    1

    Par défaut

    Bonjour,
    si deux individus ont le même coût minimum on choisit selon l'ordre des individus, donc je commence par l'individus 1 qui a le coût minimum(=coût minimum ind2) puis j'efface l'ind 1 et l'individu choisi (ex: A) puis je passe à l'individus 2...

    Mathilde

  4. #4
    Membre confirmé
    Homme Profil pro
    Consultant Finance/Assurance
    Inscrit en
    décembre 2013
    Messages
    161
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultant Finance/Assurance

    Informations forums :
    Inscription : décembre 2013
    Messages : 161
    Points : 605
    Points
    605

    Par défaut

    Bonjour,

    Un bout de code qui pourrait t'aider à résoudre ton 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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    data have;
      input ind1 $ ind2 $ cout;
    datalines;
    1 A 2
    1 B 5 
    1 C 3
    2 A 1
    2 B 10 
    2 C 5
    3 A 5
    3 B 4 
    3 C 55
    ;
    Run;
     
    Proc sort data = have out = test;
    By ind1 cout;
    Run;
     
     
    Data test2 (drop = liste);
    Set test;
    By ind1;
    Length Liste $ 1000;
    Retain Liste;
    If Find(Liste,strip(ind1)) = 0 and Find(Liste,strip(ind2)) = 0 then do;
    	Liste = Catx(" ",Liste,Ind1, Ind2);
    	Output;
    End;
    Run;
    Je vois que tu utilises pas mal de "By" dans la proc summary par exemple, je te conseille d'utiliser "Class" à la place qui te permet de ne pas trier ta table en amont.
    Autre point, tu utilises la fonction Lag dans un instruction conditionnelle ce qui est à éviter car cette fonction peu être piégeuse si on ne maitrise pas son fonctionnement. Pour ce cas tu peux plutôt utiliser les marqueurs Fisrt et Last qui feront parfaitement le job.

    Bon courage

  5. #5
    Nouveau Candidat au Club
    Inscrit en
    juin 2009
    Messages
    3
    Détails du profil
    Informations forums :
    Inscription : juin 2009
    Messages : 3
    Points : 1
    Points
    1

    Par défaut

    Bonjour
    merci beaucoup pour la réponse.
    Cela fonctionne bien sauf que j'ai des identifiants en chiffre et donc le find ne fonctionne pas quand j'ai une personne avec un numéro 13 par exemple et une autre en 130.

    Cordialement
    Mathilde

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

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

    Informations forums :
    Inscription : mai 2011
    Messages : 672
    Points : 1 557
    Points
    1 557

    Par défaut

    Bonjour,

    normalement avec une configuration normale, tu dois pouvoir traiter un million d'individus sans trop de problème (tout dépend de ta longueur d'identifiant ind2 en fait).

    La recherche se fait en O(1) contrairement à la proposition de flo qui est en O(n) et est rapidement limitée en terme de stockage de clé déjà retenues.

    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
    data have;  input ind1 $ ind2 $ cout;
    datalines;
    1 A 2
    1 B 5 
    1 C 3
    2 A 1
    2 B 10 
    2 C 5
    3 A 5
    3 B 4 
    3 C 55
    ;
     
     
    run;
     
     
    data to_Have_and_Have_not;
    set have;
    if _n_=1 then     do;
                declare hash YesWeCan();
                YesWeCan.definekey('ind2');
                YesWeCan.definedone();
     
                declare hash Data(ordered:'a');
                Data.definekey('ordre');
                Data.definedata('ordre','ind1','ind2','cout');
                Data.definedone();
                declare hiter HData('Data');
                    end;
     
     
    retain min_cout num_ordre;
    by ind1;
    ordre=_n_ ;
     
     
    if first.ind1     then do;    rcData=Data.clear();
                                min_cout=.;
                                num_ordre=.;
                         end;
    rcYesWeCan=YesWeCan.check();                
     
     
    if rcYesWeCan^=0 then     do;
                    if min_cout=. then     do;
                                    num_ordre=ordre;
                                    min_cout=cout;
                                        end;
                                else if cout<min_cout then     do;
                                                                num_ordre=ordre;
                                                                min_cout=cout;
                                                            end;
                    rcData=Data.add();
                            end;
     
     
     
    if last.ind1    then    do;
        if min_cout=.     then     do;
                                ind2="";cout=.;output;
                                end;
     
                        else    do;
                                      rcHData=HData.first();
                                      do while (rcHData=0);
                              if num_ordre=ordre then     do;
                                                          output;
                                                          RCYesWeCan=YesWeCan.add();
                                                          end;
                                      rcHData=HData.next();
                                      end;
                                  end;
                              end;
    keep ind1 ind2 cout;
    run;
     
     
    proc print data=to_Have_and_Have_not;run;
    Obs. ind1 ind2 cout
    1 1 A 2
    2 2 C 5
    3 3 B 4

Discussions similaires

  1. Insertion puis suppression de saut de page dans excel
    Par tarmin dans le forum Macros et VBA Excel
    Réponses: 12
    Dernier message: 16/11/2011, 11h27
  2. Réponses: 1
    Dernier message: 13/06/2007, 17h20
  3. [DOS] Script de recherche puis suppression
    Par villegente dans le forum Scripts/Batch
    Réponses: 1
    Dernier message: 13/02/2007, 10h53
  4. [dbExpress]Select marche 1 fois, puis plus rien !
    Par qi130 dans le forum Bases de données
    Réponses: 7
    Dernier message: 08/12/2005, 23h13
  5. [mysql]SELECTION couple distinct
    Par LE NEINDRE dans le forum Requêtes
    Réponses: 2
    Dernier message: 06/10/2005, 09h32

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