3
votes

Sélectionnez une observation si elle en a une autre dans les 24 heures qui suivent

J'essaie de créer un tableau qui ne renseigne les entrées d'un contact d'un client à un numéro d'entreprise que s'il n'a PAS été contacté pour la première fois à un numéro de domicile dans les 24 heures précédant la tentative d'attribution du numéro d'entreprise.

Donc si j'ai

1 20MAY2018:06:24:28 B
2 24MAY2018:06:24:28 B
5 29MAY2018:07:24:28 B
5 29MAY2018:08:24:28 B

Je veux pouvoir obtenir

DATA HAVE;
 INPUT ID RECORD DATETIME. TYPE;
 FORMAT RECORD DATETIME.;
 CARDS;
 1 17MAY2018:06:24:28 H
 1 18MAY2018:05:24:28 B
 1 20MAY2018:06:24:28 B
 2 20MAY2018:07:24:28 H
 2 20MAY2018:08:24:28 B
 2 22MAY2018:06:24:28 H
 2 24MAY2018:06:24:28 B
 3 25MAY2018:06:24:28 H
 3 25MAY2018:07:24:28 B
 3 25MAY2018:08:24:28 B
 4 26MAY2018:06:24:28 H
 4 26MAY2018:07:24:28 B
 4 27MAY2018:08:24:28 H
 4 27MAY2018:09:24:28 B
 5 28MAY2018:06:24:28 H
 5 29MAY2018:07:24:28 B
 5 29MAY2018:08:24:28 B
 ;
RUN;

J'ai essayé d'ajouter un décompte à l'ID mais Je ne sais pas comment j'utiliserais cela, ou s'il existe un moyen d'utiliser une sous-requête dans un proc sql pour créer un nombre d'observations qui en ont plus d'une sur une période de 24 heures.

p>

sas

0 commentaires

4 Réponses :


0
votes

Je crois que j'ai compris!

J'ai des tables HAVEA et HAVEB hébergeant respectivement des entrées de type H et de type B.

Ensuite, j'ai exécuté les PROC SQL suivants.

PROC SQL;
CREATE TABLE WANTA AS
SELECT A.RECORD AS PREVIOUS_CALL, B.* FROM HAVEB B
JOIN HAVEA A ON (B.ID=A.ID AND A.RECORD LE B.RECORD);

CREATE TABLE WANTB AS
SELECT * FROM WANTA
GROUP BY ID, RECORD
HAVING PREVIOUS_CALL = MAX(PREVIOUS_CALL);

CREATE TABLE WANTC AS
SELECT * FROM WANTB
WHERE INTNX('HOUR',RECORD,-24,'SAME') GT PREVIOUS_CALL;
QUIT;

S'il vous plaît laissez-moi savoir si ce n'est pas une réponse durable pour de plus grandes quantités de données ou s'il existe une bien meilleure méthode pour aborder cela.


0 commentaires

1
votes

Donc, votre approche fonctionnera, mais sera assez désordonnée avec de grands nombres - comme vous faites une jointure cartésienne dans ID. Si chaque ID a peu d'enregistrements, ce n'est pas si mal, mais si chaque ID contient de nombreux enregistrements, vous établissez beaucoup de connexions.

Heureusement, il existe un moyen simple de le faire dans SAS!

data want;
  do _n_ = 1 by 1 until (last.id);  *for each ID:;
    set have;
    by id;    
    if first.id then last_home=0;   *initialize last_home to 0;
    if type='H' then last_home = record;  *if it is a home then save it aside;
    if type='B' and intck('Hour',last_home,record,'c') gt 24 then output;   *if it is business then check if 24 hours have passed;
  end;
  format last_home datetime.;
run;
  • J'utilise une boucle DoW, mais ce n'est vraiment pas obligatoire, je l'aime simplement du point de vue de la clarté (cela indique clairement que je fais quelque chose au niveau de la répétition d'ID). Vous pouvez supprimer cette boucle et ajouter un RETAIN pour last_home et ce serait la même chose.
  • J'utilise INTCK au lieu d'INTNX - encore une fois, c'est pour plus de clarté, votre INTNX est bien aussi, mais INTCK fait juste la comparaison, tandis qu'INTNX sert à avancer les dates d'un montant. J'utilise celui qui correspond à ce que j'essaie de faire, pour que quelqu'un qui lit le code puisse voir facilement ce que je fais.

Ce sera beaucoup plus rapide que SQL sur des ensembles de données plus volumineux, si pour aucune autre raison que cela ne passe les données qu'une seule fois. SQL le fera nécessairement plusieurs fois, même si vous ne séparez pas HAVEA / HAVEB et faites cela dans la requête SQL.


2 commentaires

C'est tellement ennuyeux, maintenant que je le vois, c'est parfaitement logique, mais je ne pourrais pas pour la vie de moi le trouver moi-même. Avec cette étape de données, les principaux besoins avant cela sont de s'assurer que les données sont dans une seule table et triées par ID puis par enregistrement, n'est-ce pas?


Droite. Et vous pouvez appliquer le RECORD en l'ajoutant à l'instruction BY sans problème réel. Il n'est pas nécessaire qu'il soit dans un seul ensemble de données, vous pouvez faire quelque chose de similaire s'il est en deux (soit HAVEA et HAVEB, avec une MERGE, soit plusieurs ensembles de données s'étendant sur plusieurs jours, simplement en les ajoutant à l'instruction SET).



0
votes

Vous effectuez une sélection pour obtenir le jeu de résultats final sans créer de tableaux intermédiaires. Voici deux alternatives:

Première manière

Semblable à votre «comprendre». Une jointure réflexive avec regroupement détecte les appels «to_home» avant les appels «to_business» qui ne se sont PAS produits au cours des dernières 24 heures (86 400 secondes)

  create table want2 as
  select 
    business.*
  from
    have as business
  where
    business.type = 'B'
    and
    not exists (
      select * from have as home
      where home.id = business.id
        and home.type = 'H'
        and home.call_dt < business.call_dt
        and home.call_dt >= business.call_dt - 86400
    )
  ;

Second manière

Effectuez une vérification NON existentielle, pour un appel to_home dans les 24 heures précédentes, pour chaque appel to_business.

proc sql;
  create table want as
  select distinct
    business.*
  from have as business
  join have as home
    on business.id = home.id
       & business.type = 'B'
       & home.type = 'H'
       & home.CALL_DT < business.CALL_DT
   group by
     business.call_dt
   having
     max(home.call_dt) < business.call_dt - 86400
       ;


0 commentaires

0
votes

Une solution HASH a quelques dépendances (quantité de données et RAM) ... mais c'est une autre alternative

DATA HAVE;
 INPUT ID RECORD DATETIME. TYPE $;
 FORMAT RECORD DATETIME.;
 CARDS;
 1 17MAY2018:06:24:28 H
 1 18MAY2018:05:24:28 B
 1 20MAY2018:06:24:28 B
 2 20MAY2018:07:24:28 H
 2 20MAY2018:08:24:28 B
 2 22MAY2018:06:24:28 H
 2 24MAY2018:06:24:28 B
 3 25MAY2018:06:24:28 H
 3 25MAY2018:07:24:28 B
 3 25MAY2018:08:24:28 B
 4 26MAY2018:06:24:28 H
 4 26MAY2018:07:24:28 B
 4 27MAY2018:08:24:28 H
 4 27MAY2018:09:24:28 B
 5 28MAY2018:06:24:28 H
 5 29MAY2018:07:24:28 B
 5 29MAY2018:08:24:28 B
 ;
RUN;

 /* Keep only HOME TYPE records and 
     rename RECORD for using in comparision */
Data HOME(Keep=ID RECORD rename=(record=hrecord));
 Set HAVE(where=(Type="H"));
Run;

Data WANT(Keep=ID RECORD TYPE);
   /* Use only BUSINESS TYPE records */
 Set HAVE(where=(Type="B"));

  /* Set up HASH object */    
 If _N_=1 Then Do;
   /* Multidata:YES for looping through 
       all successful FINDs */
  Declare HASH HOME(dataset:"HOME", multidata:'yes');
  home.DEFINEKEY('id');
  home.DEFINEDATA('hrecord');
  home.DEFINEDONE();
   /* To prevent warnings in the log */
  Call Missing(HRECORD);
 End;

   /* FIND first KEY match */
 rc=home.FIND();
   /* Successful FINDs result in RC=0 */
 Do While (RC=0);
   /* This will keep the result of the most recent, in datetime,
       HOME/BUS record comparision */
   If intck('Hour',hrecord,record,'c') > 24 Then Good_For_Output=1;
   Else Good_For_Output=0;
    /* Keep comparing HOME/BUS for all HOME records */
   rc=home.FIND_NEXT();
 End;

 If Good_For_Output=1 Then Output;
Run;


0 commentaires