Resources

Format Data Set from Parent/Child Links

 /****************************************************************/
 /*          S A S   S A M P L E   L I B R A R Y                 */
 /*                                                              */
 /*    NAME: ISHLINK                                             */
 /*   TITLE: Format Data Set from Parent/Child Links             */
 /* PRODUCT: QC                                                  */
 /*  SYSTEM: ALL                                                 */
 /*    KEYS: Ishikawa Diagrams,                                  */
 /*   PROCS: ISHIKAWA                                            */
 /*    DATA:                                                     */
 /*                                                              */
 /*    MISC: %ISHALVL adds the _LEVEL_ variable to the input     */
 /*          data set.                                           */
 /*                                                              */
 /*          %ISHSORT organizes the observations into the        */
 /*          proper order.  %ISHSORT does not rely on output     */
 /*          from %ISHALVL so it can be used any time an         */
 /*          Ishikawa data set becomes 'unorderly'.              */
 /*                                                              */
 /*          These macros do not check the parent/arrow links    */
 /*          for errors.                                         */
 /*                                                              */
 /****************************************************************/

options ps=60 ls=80;

%macro ishalvl( data, arrow, parent );

   /* DATA    input data set           */
   /* ARROW   arrow  variable          */
   /* PARENT  parent variable          */
   /* Output  saved in WORK.ISHIKAWA   */

   proc sort data=&data out=work;
      by &arrow;
      run;

   data work;
      set work;
      by &arrow;
      if first.&arrow then
         output;
      else
         put 'Warning: Duplicates deleted.';
      run;

   data work;
      set work;
      if &parent=' ' then blevel=0;
      run;

   %do level=1 %to 9;

      proc sort data=work;
         by &parent;
         run;

      data subset;
         set work;

         elevel = &level;
         if blevel = elevel-1 then output;

         keep &arrow elevel;
         run;

      proc sort data = subset;
         by &arrow;
         run;

      %let done=0;

      data work;
         merge work  (rename=(&parent=key) in=in)
               subset(rename=(&arrow=key));
         by key;

         if elevel ^= ' ' then blevel = elevel;

         if &done = 0 and blevel = ' ' then
            call symput('done', '1');

         if in then output;

         rename key = &parent;
         drop elevel;
         run;

      %if &done=0 %then %let level = 10;
      %end;

   /* To replace the input data set: change ishikawa to &data */

   data ishikawa;
      set work;
      rename blevel = _level_;
      if 0 <= blevel & blevel <= 9;
      run;

   %mend;


%macro ishsort( data, arrow, parent );

   /* DATA    input data set           */
   /* ARROW   arrow  variable          */
   /* PARENT  parent variable          */
   /* Output  saved in WORK.ISHIKAWA   */

   data level0 level1 level2 level3 level4
        level5 level6 level7 level8 level9;
      set &data end=end;
      retain max;
      drop   max;

      max = max( max, _level_ );

      if      _level_  = 0 then output level0;
      else if _level_  = 1 then output level1;
      else if _level_  = 2 then output level2;
      else if _level_  = 3 then output level3;
      else if _level_  = 4 then output level4;
      else if _level_  = 5 then output level5;
      else if _level_  = 6 then output level6;
      else if _level_  = 7 then output level7;
      else if _level_  = 8 then output level8;
      else if _level_  = 9 then output level9;

      if end then call symput( 'first', max );
      run;

   %let first=%left(&first);

   data   level&first;
      set level&first;
      key = &parent;
      run;

   %do i=&first %to 1 %by -1;

      proc sort data=level&i;
         by key;
         run;

      %let j=%eval(&i-1);

      data   level&j;
         set level&j;
         key = &arrow;
         run;

      proc sort data=level&j;
         by key;
         run;

      data   level&j;
         set level&j(in=in) level&i;
         by key;
         if in then temp=&parent;
         retain temp;
         drop key;
         rename temp=key;
         run;

      %end;

   /* To replace the input data set: change ishikawa to &data */

   data ishikawa;
      set level0;
      drop key;
      run;

   %mend;

data one;                    /* input data set             */
   length a b _text1_ $ 2;
   input  a b _text1_;       /* B is A's parent            */
   cards;
      C8   B3   c
      B1   A0   b
      G1   F1   g
      B2   A0   b
      C5   B1   c
      E1   D1   e
      C9   B1   c
      B3   A0   b
      C7   B2   c
      A0   .    a
      C1   B2   c
      C3   B2   c
      C2   B1   c
      D1   C1   d
      C4   B3   c
      F1   E1   f
      C6   B3   c
      ;

%ishalvl( one,      a, b );  /* compute values for _LEVEL_ */
%ishsort( ishikawa, a, b );  /* sort into proper order     */

proc ishikawa data=ishikawa;
   run;