SAS中带滞后的前后向法填充缺失值

SAS中带滞后的前后向法填充缺失值,sas,lag,missing-data,Sas,Lag,Missing Data,假设您有一个表,其中包含每个计数器的用户名、计数器和分数 data have; input user $ counter score; cards; A 1 . A 2 . A 3 40 A 4 . A 5 20 A 6 . B 1 30 B 2 . C 1 . C 2 . C 3 . ; run; 某些计数器之间缺少一些分数,您希望将分数与上一个计数器相同。因此,结果如下所示: A 1 40 A 2 40 A 3 40 A 4 40 A 5 20 A 6 20 B 1 30 B 2 30

假设您有一个表,其中包含每个计数器的用户名、计数器和分数

data have;
input user $  counter  score;
cards;
A 1 .
A 2 .
A 3 40
A 4 .
A 5 20
A 6 .
B 1 30
B 2 .
C 1 .
C 2 .
C 3 .
;
run;
某些计数器之间缺少一些分数,您希望将分数与上一个计数器相同。因此,结果如下所示:

A 1 40
A 2 40
A 3 40
A 4 40
A 5 20
A 6 20
B 1 30
B 2 30
C 1 .
C 2 .
C 3 .
data result1a;
  set have(keep=user);
  by user;

  *Look ahead;
    merge have have(firstobs=2 keep=score rename=(score=_NextScore));

    if first.user then do;
        if score= . then score=_NextScore;
        end;
    else do;
        _PrevScore = lag(score);
        if score= . then score=_PrevScore;
    end;
    output;
run;
proc sort data = result1a out= result1b; 
by user descending counter ;
run;
我通过如下所示的
lag
函数成功地向前填充了缺失的分数值:

A 1 40
A 2 40
A 3 40
A 4 40
A 5 20
A 6 20
B 1 30
B 2 30
C 1 .
C 2 .
C 3 .
data result1a;
  set have(keep=user);
  by user;

  *Look ahead;
    merge have have(firstobs=2 keep=score rename=(score=_NextScore));

    if first.user then do;
        if score= . then score=_NextScore;
        end;
    else do;
        _PrevScore = lag(score);
        if score= . then score=_PrevScore;
    end;
    output;
run;
proc sort data = result1a out= result1b; 
by user descending counter ;
run;
然后,我使用
计数器上的
降序
函数将表向后排序,如下所示:

A 1 40
A 2 40
A 3 40
A 4 40
A 5 20
A 6 20
B 1 30
B 2 30
C 1 .
C 2 .
C 3 .
data result1a;
  set have(keep=user);
  by user;

  *Look ahead;
    merge have have(firstobs=2 keep=score rename=(score=_NextScore));

    if first.user then do;
        if score= . then score=_NextScore;
        end;
    else do;
        _PrevScore = lag(score);
        if score= . then score=_PrevScore;
    end;
    output;
run;
proc sort data = result1a out= result1b; 
by user descending counter ;
run;
最后,我将再次使用
lag
函数在raaranged表中向前填充缺失的值(根据初始表向后填充),如下所示

我在
do loop
中使用了
lag
函数,因为我想在每个步骤中更新之前的值(例如,值40将从组中的第一个分数一直带到最后一个分数)

然而,我得到了奇怪的结果。所有缺少的值都不会得到实际值。有没有关于修复最后一个数据步骤的想法

data result1c;
set result1b;
by user;

   if first.user then do;
        if score= . then score=_NextScore;
        else score = score;

        end;
   else do;
        _PrevScore = lag(score);
        if score= . then 
        score=_PrevScore;
        else score = score;
   end;
   output;
run;
lag()
是一个经常被误解的函数。该名称意味着,当您调用它时,SAS会返回上一行并获取该值,但事实并非如此

实际上,
lag()
是一个函数,它创建了一个具有n个值的“队列”。当您调用
lag(x)
时,它将x的当前值推送到该队列中,并从中读取以前的值(当然,推送每行只发生一次)。因此,如果在一个条件中有
lag()
,则只有在满足该条件时才会发生推送

要解决您的问题,您需要为每一行运行lag()函数,并在更正分数后运行:

data result1c;
set result1b;
by user;
if first.user then do;
    if score= . then score=_NextScore;
    else score = score;
end;
else do;
    if score= . then 
    score=_PrevScore;
    else score = score;
end;
_PrevScore = lag(score);
output;
run;
编辑:我被延迟的误用所困扰,没有提出一个可行的替代方案。因为您正在修改分数,所以使用滞后是个坏主意。我们将在这里工作:

data result1c;
set result1b;
by user;
retain _PrevScore;
if first.user then do;
    if score= . then score=_NextScore;
    else score = score;
end;
else do;
    if score= . then 
    score=_PrevScore;
    else score = score;
end;
_PrevScore = score;
output;
run;

不需要使用
lag
,使用
retain
(或同等工具)。这里有一个双道循环解决方案,它在一个数据步骤中完成(并且,有效地,一次读取-它缓冲读取,因此这与单次读取一样有效)

首先,我们循环遍历数据集以获得找到的第一个分数,这样我们就可以获取初始prev_分数值。然后设置它,并重新循环该用户的行并输出。这里没有实际的
retain
,因为我自己在做循环,但这类似于如果有
retain prev_分数这是一个正常的数据步循环。我实际上并没有保留它,因为我希望它在遇到新用户时丢失

data want;
  do _n_ = 1 by 1 until (last.user);
    set have;
    by user;
    if missing(first_score) and not missing(score) then 
      first_score = score;

  end;
  prev_score = first_score;
  do _n_ = 1 by 1 until (last.user);
    set have;
    by user;
    if missing(score) then
      score = prev_score;
    prev_score = score;
    output;
  end;
run;

您的解决方案似乎合乎逻辑,但就在
输出之前,
\u PrevScore=lag(score)
仅给出两个40值。如果我把它放在用户的
后面然后我得到三个40值。但我需要四个40的值。它仍然不能给出解决方案,但可能是因为我之前的步骤,如果我处理错误的话。正如@Joe所建议的那样,只需一个数据步骤就更容易了。谢谢…这看起来也很有效,但我得到了两个奇怪的结果:所有缺少的值都是零值(我不知道为什么)。第二个问题是前两个值(user=A和counter 1,2)没有得到40个值,仍然缺少(或者是零,第一个奇怪的问题)它们不适合我,所以我不确定为什么它们适合你。哎呀!现在我明白了。我误解了你的第一次得分,我以为是第一次得分。现在它可以正常工作了:)多谢了洛塔,也许名称应该有所不同,这让人困惑。