如何使用 DO LOOP WITH PARTITION

how to use DO LOOP WITH PARTITION

我有一个包含 3 列的数据集 - 'account'、'num_owners' 和 'date' - 按 'account' 和 'date' 排序。 我想为每个帐户标记 num_owners(向上或向下)的变化,使用 SAS DO 循环:

DATA test ;
    SET work.Owners_Change ;
    LENGTH change . ;
    RETAIN change ' ' ;
    ARRAY A[1] num_owners ;
    DO i=1 TO DIM(A) ;
        IF A[i+1] = A[i]
        THEN change = 'no change' ;
        IF A[i+1] > A[i]
        THEN change = 'Add' ;
        IF A[i+1] < A[i]
        THEN change = 'Subtract' ;
    END ;
RUN ;

它给我一个错误:错误:第 32 行第 6 列的数组下标超出范围。

我怀疑您想使用 LAG() 而不是数组来测试 NUM_OWNERS 的当前值是否与先前的值不同。

data test ;
  set work.Owners_Change ;
  length change . ;
  if num_owners = lag(num_owners) then change = 'no change' ;
  if num_owners > lag(num_owners) then change = 'Add' ;
  if num_owners < lag(num_owners) then change = 'Subtract' ;
run;

小心 LAG(),不要有条件地调用它,否则它使用的值链将被中断。请注意我没有在辅助 if 语句之前包含 else。您也可以将滞后值存储到另一个变量中并对其进行测试。

data test ;
  set work.Owners_Change ;
  length change . ;
  num_owners_lagged=lag(num_owners);
  if num_owners = num_owners_lagged then change = 'no change' ;
  else if num_owners > num_owners_lagged  then change = 'Add' ;
  else change = 'Subtract' ;
run;

所以,你有这一行:

ARRAY A[1] num_owners ;

这就创建了一个维数为1的数组。A[1]是一个合法的语句,地址是num_ownersA[2] 或更高,或 A[0] 或更低,将失败,因为数组中只定义了一项。

然后你在循环中有这个语句:

        IF A[i+1] = A[i]
        THEN change = 'no change' ;

这表示“如果 A 数组中的第二项等于 A 数组中的第一项”;但这不起作用,因为没有第二项。


快速 SAS 数组教程:与 R 或 Python 不同,SAS 中的数组只是列的列表并且可以访问当前数据行上的值 ,没有别的。这是一种编程方法,允许您对一组变量执行某些操作,通常是一组变量具有有意义的顺序(但并非总是如此)。

在 SAS 中,您可以 在几乎所有上下文中对当前行进行操作,但有一些非常具体的例外 - SAS 的主要工作方式类似于 R 中的循环或Python,例如,总是,有点像:

data a; 
  set b;
  if x = 1 then y = 5;
run;

在 python 中可能更像是 (psuedocode):

for b_row in b.rows():
  if b_row[x] = 1 then b_row[y] = 5;

但是就像在 Python 中一样,您不能接受 b_row[x+1] 并期望它会让您进入下一行 b(您必须以不同的方式处理它),您也无法通过说 A[i+1] 访问 SAS 中的下一行。

这里最好的选择是进行合并,将下一行合并到当前行:

data want;
  merge sashelp.class sashelp.class(firstobs=2 keep=age rename=age=age_next);
  if age = age_next then sameage=1;
run;

或者使用lag函数,主要操作“下一个”行而不是“上一个”行。

data want;
  set sashelp.class;
  if lag(age) = age then sameage=1;
run;

这是不同的 - 请注意 sameage 结束的位置 - 但你可以通过对输入数据集 以相反的顺序 进行排序来使其以相同的方式工作,然后你'重新得到相同的结果。

    proc sort data=sashelp.class out=class;
      by descending name;
    run;
    
    data want;
      set class;
      if lag(age) = age then sameage=1;
    run;