Estoy atascado para resolver este problema en SAS. Probablemente no sea tan complicado, pero intenté cosas con retener y hacer bucles que no funcionaron.

Básicamente, cada ID tiene datos sobre cada fecha. En base a otras variables pueden entrar en un estado de disminución (paso variable> 0) y en ocasiones cumplirán la condición final1. Si se cumple la condición 1 = 1, necesito marcar el "episodio" comenzando al principio de la disminución.

A continuación se muestra un ejemplo de cómo se ven mis datos y el indicador de columna es lo que necesito. He puesto los datos en orden ascendente para que los entendamos

    ID  date    step    condition1  flag
    z   1       0       .   
    z   2       0       .   
    z   3       0       .   
    z   4       1       .           TRUE
    z   5       2       .           TRUE
    z   6       2       .           TRUE
    z   7       3       .           TRUE
    z   8       4       .           TRUE
    z   10      4       .           TRUE
    z   11      4       1           TRUE
    z   12      4       .   
    z   13      4       .   
    z   14      0       .   
    z   15      0       .   
    z   16      0       .   
    z   17      1       .   
    z   18      2       .   
    z   19      2       .   
    z   20      0       .   
    z   21      0       .   

Editar: tabla con la variable utilizada para determinar la disminución

ID  date    quantity    step    condition1  flag
z   1       90          0       .   
z   2       90          0       .   
z   3       100         0       .   
z   4       90          1       .           TRUE
z   5       80          2       .           TRUE
z   6       80          2       .           TRUE
z   7       50          3       .           TRUE
z   8       0           4       .           TRUE
z   10      0           4       .           TRUE
z   11      0           4       1           TRUE
z   12      0           4       .   
z   13      0           4       .   
z   14      40          0       .   
z   15      50          0       .   
z   16      60          0       .   
z   17      40          1       .   
z   18      40          2       .   
z   19      30          2       .   
z   20      60          0       .   
z   21      60          0       .   

Intenté ordenarlo por ID y fecha descendente, lo que parece tener sentido.

proc sort data= have; 
by id descending  date ;
run;

Esta es una de las muchas cosas que intenté, pero se atasca; (Editado)

DATA want  ;
SET have;
if four=1 then do;
 do until (step<1) ; flag=1;  output;
 end;
end;
run;

Cualquier ayuda apreciada. Probablemente solo necesite una pista en la dirección correcta. Gracias

sas
0
DURAL 16 oct. 2018 a las 15:55

2 respuestas

La mejor respuesta

Dentro del procesamiento grupal que requiere una evaluación sobre un conjunto de filas, que debe aplicarse a las mismas filas, se puede realizar utilizando un patrón de codificación "DOW en serie". Sus datos pueden tener múltiples segmentos dentro de un grupo, por lo que todo se anidaría en un bucle do externo.

Ejemplo

Sus restricciones de combinación de pasos y condiciones no se explican completamente, por lo que la lógica de ejemplo podría no cubrir todos los casos.

En este ejemplo, index_first_after_last_zero rastrea el inicio de una serie de filas con step > 0 y termina con condition1 = 1

data want;
  do until (last.id);

    segment = sum(segment,1);  * <------ helper for understanding logic;

    * 'measuring loop' that computes or tracks some multi-row condition within group;
    do index = 1 by 1 until (condition1 or last.id);
      set have;       * <------ SET inside loop;
      by id date;     * <------ BY for last.id and ensures dates are ordered;

      * track start of last run of non-zero steps;
      if step=0 then 
        index_first_after_last_zero = index + 1;
    end;

    * track end of run flag;
    segment_end_condition = condition1;

    * end of loop value is fixed at start of loop and thus not affected by automatic BY 1 increment;
    * thus 1 to index iterates same number of rows as the 'measuring' loop;
    do index = 1 to index;

      set have;     * <------ second SET use a separate file buffer than first SET;

      * apply flag value -- missing for pre-run rows, and end of run flag to run rows;
      if index < index_first_after_last_zero 
        then flag = .;
        else flag = segment_end_condition;

      OUTPUT;
    end;

  end;
run;
1
Richard 16 oct. 2018 a las 17:31

No puede usar do until así en un paso de datos; iterará, pero no leerá ninguna observación adicional del conjunto de datos de entrada.

Creo que la idea clave que necesitas es mantener variables de estado separadas para recordar lo que ya has visto:

proc sort data=have; 
  by id date;
run;

data want;
  retain episode_started episode_finished;
  set have;
  by id;
  if first.id then do;
    episode_started = 0;
    episode_finished = 0;
  end;
  if step > 0 then episode_started = 1;
  if episode_started and not episode_finished then flag = 'TRUE';
  output;
  if condition1 then episode_finished = 1;
run;

No lo he probado, pero debería estar cerca. Puede revisar las dos marcas agregadas en el conjunto de datos de salida para comprender cuándo y cómo se configuran. Podría lograr lo mismo utilizando una única variable de estado con más de dos valores, pero creo que el código anterior es más claro.

1
Chris Long 16 oct. 2018 a las 17:07