SAS: как избежать множественных левых соединений? - PullRequest
0 голосов
/ 04 апреля 2020

У меня есть такой набор данных (только с большим количеством учетных записей и, следовательно, наблюдений) * Переменная 1001 *

data dataset;
input account_id month date9. default_flag;
format month date9.;
datalines;
22 31JAN2004 0
22 29FEB2004 0
22 31MAR2004 0
22 30APR2004 0
22 31MAY2004 0
22 30JUN2004 0
22 31JUL2004 0
22 31AUG2004 0
22 30SEP2004 0
22 31OCT2004 0
22 30NOV2004 0
22 31DEC2004 0
22 31JAN2005 0
22 28FEB2005 0
22 31MAR2005 0
22 30APR2005 0
22 31MAY2005 1
;
run;

default_flag указывает, является ли учетная запись по умолчанию (default_flag=1) или нет (default_flag=0 ).

Я хочу создать флаговую переменную по умолчанию для X-месяцев defXMON_flag, которая равна 1, если учетная запись вводит значение по умолчанию в следующие X месяцев, и существует как минимум X месяцев наблюдений. Если учетная запись вводит значение по умолчанию, но наблюдений меньше, чем X месяцев, тогда переменная будет равна 3.

Мне нужно создать несколько таких переменных для нескольких разных X. Допустим, я хочу создать две такие переменные - одна для X = 12 месяцев (def12MON_flag) и одна для X = 15 месяцев (def15MON_flag).

Я придумал следующий код, который дает нужные мне результаты:

proc sql noprint;
            create table defaults as
             select a.account_id, a.month, a.default_flag, 
                    sum(b.default_flag) as nr_defaults_12 format = comma17.,
                    count(distinct b.month) as nr_months_12,
                    case when a.default_flag = 0 
                              and coalesce(calculated nr_defaults_12, 0) eq 0 
                              and coalesce(calculated nr_months_12, 0) = 12 then 0 
                         when a.default_flag = 0 
                              and coalesce(calculated nr_defaults_12, 0) ne 0 
                              and coalesce(calculated nr_months_12, 0) = 12 then 1
                         when a.default_flag = 0 
                              and coalesce(calculated nr_defaults_12, 0) eq 0 
                              and coalesce(calculated nr_months_12, 0) ne 12 then 2 
                        when a.default_flag = 0 
                             and coalesce(calculated nr_defaults_12, 0) ne 0 
                             and coalesce(calculated nr_months_12, 0) ne 12 then 3
                        else . 
                    end as def12MON_flag,

                    sum(c.default_flag) as nr_defaults_15 format = comma17.,
                    count(distinct c.month) as nr_months_15,
                    case when a.default_flag = 0 
                              and coalesce(calculated nr_defaults_15, 0) eq 0 
                              and coalesce(calculated nr_months_15, 0) = 15 then 0 
                         when a.default_flag = 0 
                              and coalesce(calculated nr_defaults_15, 0) ne 0 
                              and coalesce(calculated nr_months_15, 0) = 15 then 1
                         when a.default_flag = 0 
                              and coalesce(calculated nr_defaults_15, 0) eq 0 
                              and coalesce(calculated nr_months_15, 0) ne 15 then 2 
                        when a.default_flag = 0 
                             and coalesce(calculated nr_defaults_15, 0) ne 0 
                             and coalesce(calculated nr_months_15, 0) ne 15 then 3
                        else . 
                    end as def15MON_flag

                from ( select account_id, month, default_flag from dataset where default_flag = 0) a
                     left outer join ( select account_id, default_flag, month from dataset ) b
                        on 1=1 
                            and a.account_id = b.account_id 
                            and b.month between intnx('month', a.month, 1, 'end') 
                                                        and intnx('month', a.month, 12, 'end')

                     left outer join ( select account_id, default_flag, month from dataset ) c
                        on 1=1 
                            and a.account_id = c.account_id 
                            and c.month between intnx('month', a.month, 1, 'end') 
                                                        and intnx('month', a.month, 15, 'end')
                group by a.account_id, a.month, a.default_flag 
                order by a.account_id, a.month;
quit;
run;

Это мой конечный результат - не важная часть, важная часть - создание таблицы defaults, которую мне нужно оптимизировать.

    PROC SQL;
    CREATE TABLE RESULT AS
    SELECT T.*, S.DEF12MON_FLAG, S.DEF15MON_FLAG
    FROM DATASET T
    LEFT JOIN DEFAULTS S 
    ON T.ACCOUNT_ID = S.ACCOUNT_ID
    AND T.MONTH = S.MONTH
    ORDER BY ACCOUNT_ID, MONTH
    ;

Однако проблема с этим кодом является то, что он использует два левых соединения огромного набора данных при создании таблицы defaults (в действительности, мне нужно было бы использовать еще больше левых объединений для большего количества defXMON_flag переменных), и его невозможно запустить из-за размера эти наборы данных. Можно ли получить тот же результат без тех левых соединений? Можете ли вы предложить более эффективный способ вычисления def12MON_flag и def15MON_flag с тем же результатом, что и этот код?

1 Ответ

0 голосов
/ 06 апреля 2020

Итак, насколько я понял, вы хотите, чтобы ваш результат выглядел так: this

, если это так, шаг 1: возьмите месяц, когда account_id имеет флаг по умолчанию,

PROC SQL;    
CREATE TABLE WORK.QUERY_FOR_DATASET AS     
SELECT DISTINCT t1.account_id, 
           t1.month, 
           t1.default_flag
       FROM WORK.DATASET t1
       WHERE t1.default_flag = 1; 
QUIT;

, а затем вычислите разницу в месяце с помощью функции intck()

PROC SQL;
   CREATE TABLE WORK.QUERY_FOR_DATASET_0000 AS 
   SELECT DISTINCT t1.account_id, 
          t1.month, 
          t1.default_flag, 
          t2.month AS month_when_default_flag_1, 
          /* month_difference */
            (intck('month', t1.month, t2.month)) AS month_difference
      FROM WORK.DATASET t1
           LEFT JOIN WORK.QUERY_FOR_DATASET t2 ON (t1.account_id = t2.account_id);
QUIT;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...