L oop через каждое наблюдение в SAS - PullRequest
0 голосов
/ 07 августа 2020

Допустим, у меня есть таблица из 10000 наблюдений:

Obs X Y Z
1
2
3
...
10000

Для каждого наблюдения я создаю макрос: mymacro (X, Y, Z), где я использую X, Y, Z как входные данные. Мой макрос создает таблицу с 1 наблюдением, 4 новыми переменными var1, var2, var3, var4.

Я хотел бы знать, как от l oop до 10000 наблюдений в моем начальном наборе, и результат будет например:

Obs X Y Z Var1 Var2 Var3 Var4
1
2
3
...
10000

Обновление:

Расчет Var1, Var2, Var3, Var4:

У меня есть справочная таблица:

Z    25          26          27          28          29          30   
0    10 000      10 000      10 000      10 000      10 000      10 000   
1    10 000      10 000      10 000      10 000      10 000      10 000   
2    10 000      10 000      10 000      10 000      10 000      10 000   
3    10 000      10 000      10 000      10 000      10 000      10 000   
4    9 269       9 322       9 322       9 381       9 381       9 436   
5    8 508       8 619       8 619       8 743       8 743       8 850   
6    7 731       7 914       7 914       8 102       8 102       8 258   
7    6 805       7 040       7 040       7 280       7 280       7 484   
8    5 864       6 137       6 137       6 421       6 421       6 655   
9    5 025       5 328       5 328       5 629       5 629       5 929   
10   4 359       4 648       4 648       4 934       4 934       5 320   

И мой набор имеет вид:

Obs X   Y   Z
1   27  4   9
2           
3           
            
            
10000   

Итак, для первого наблюдения (27, 4, 9):

Var1 = (8 619+ 7 914+ 7 040 + 6 137 + 5328) / 9 322

Вар2 = (8 743+ 8 102+ 7 280+ 6 421 + 5 629) / 9 381

Так что:

Вар1 = Сумма всех чисел в столбце 27 (X), от наблюдения 5 (Z + 1) до наблюдения 9 (Z), и деленная на значение в (столбец 27 (X) - наблюдение 4 (Z))

Var2 = Сумма всех чисел в столбце 28 (X + 1), от наблюдения 5 (Z + 1) до наблюдения 9 (Z), и деленная на значение в (столбец 28 (X + 1) - наблюдение 4 (Z))

Ответы [ 2 ]

3 голосов
/ 07 августа 2020

Я бы преобразовал справочную таблицу в форму, позволяющую выполнять вычисления сразу для всех наблюдений. Так что превратите свою справочную таблицу в высокую структуру, либо переставив существующую таблицу, либо просто прочитав ее таким образом, чтобы начать с:

data ref_tall;
  input z @;
  do col=25 to 30 ;
    input value :comma9. @; 
    output;
  end;
datalines;
 0    10,000      10,000      10,000      10,000      10,000      10,000   
 1    10,000      10,000      10,000      10,000      10,000      10,000   
 2    10,000      10,000      10,000      10,000      10,000      10,000   
 3    10,000      10,000      10,000      10,000      10,000      10,000   
 4     9,269       9,322       9,322       9,381       9,381       9,436   
 5     8,508       8,619       8,619       8,743       8,743       8,850   
 6     7,731       7,914       7,914       8,102       8,102       8,258   
 7     6,805       7,040       7,040       7,280       7,280       7,484   
 8     5,864       6,137       6,137       6,421       6,421       6,655   
 9     5,025       5,328       5,328       5,629       5,629       5,929   
10     4,359       4,648       4,648       4,934       4,934       5,320   
;

Теперь возьмите свою таблицу списка HAVE:

data have;
  input id x y z;
  datalines;
1 27 4 9
2 25 2 4
;

И объедините его со справочной таблицей и сделайте свои расчеты:

proc sql ;
create table want1 as
  select a.id
       , sum(b.value)/min(c.value) as var1
  from have a
  left join ref_tall b
    on a.x=b.col
    and b.z between a.y+1 and a.z
  left join ref_tall c
    on a.x=c.col
    and c.z = a.y
  group by a.id
;
create table want2 as
  select a.id
       , sum(d.value)/min(e.value) as var2
  from have a
  left join ref_tall d
    on a.x+1=d.col
    and d.z between a.y+1 and a.z
  left join ref_tall e
    on a.x+1=e.col
    and e.z = a.y
  group by a.id
;
create table want as
   select *
   from want1 natural join want2 natural join have
;
quit;

Результаты:

Obs    id     x    y    z      var1       var2

 1      1    27    4    9    3.75864    3.85620
 2      2    25    2    4    1.92690    1.93220
2 голосов
/ 07 августа 2020

Справочная таблица может быть создана в array, что упрощает выполнение указанных вычислений. К эталонным значениям затем можно получить доступ, используя прямой адрес ссылку.

Пример

Данные справочной таблицы были перемещены в набор данных, поэтому значения можно изменять с течением времени или перезагружен из какого-либо источника, например Excel. Эталонные значения могут быть загружены в массив для использования на шаге DATA.

* reference information in data set, x property column names are _<num>;

data ref;
  input z (_25-_30) (comma9. &); 
  datalines;
0    10,000      10,000      10,000      10,000      10,000      10,000   
1    10,000      10,000      10,000      10,000      10,000      10,000   
2    10,000      10,000      10,000      10,000      10,000      10,000   
3    10,000      10,000      10,000      10,000      10,000      10,000   
4    9,269       9,322       9,322       9,381       9,381       9,436   
5    8,508       8,619       8,619       8,743       8,743       8,850   
6    7,731       7,914       7,914       8,102       8,102       8,258   
7    6,805       7,040       7,040       7,280       7,280       7,484   
8    5,864       6,137       6,137       6,421       6,421       6,655   
9    5,025       5,328       5,328       5,629       5,629       5,929   
10   4,359       4,648       4,648       4,934       4,934       5,320   
;

* computation parameters, might be a thousand of them specified;

data have;
  input id x y z;
  datalines;
1 27 4 9
;

* perform computation for each parameters specified;

data want;
  set have;

  array ref[0:10,1:30] _temporary_;

  if _n_ = 1 then do ref_row = 0 by 1 until (last_ref);
    * load reference data into an array for direct addressing during computation;
    set ref end=last_ref;
    array ref_cols _25-_30;

    do index = 1 to dim(ref_cols);
      colname = vname(ref_cols[index]);
      colnum  = input(substr(colname,2),8.);
      ref[ref_row,colnum] = ref_cols[index];
    end;
  end;

  * perform computation for parameters specified;

  array vars var1-var4;

  do index = 1 to dim(vars);
    ref_column = x + index - 1 ;   * column x, then x+1, then x+2, then x+3;

    numerator = 0;                 * algorithm against reference data;
    do ref_row = y+1 to z;
      numerator + ref[ref_row,ref_column];      
    end;

    denominator = ref[y,ref_column];

    vars[index] = numerator / denominator;  * result;
  end;

  keep id x y z numerator denominator var1-var4;
run;
...