Replace SAS:用最近邻的平均值替换缺失值
我试图找到一种快速方法,用两个最近的非缺失值的平均值替换缺失值。例如:Replace SAS:用最近邻的平均值替换缺失值,replace,sas,average,Replace,Sas,Average,我试图找到一种快速方法,用两个最近的非缺失值的平均值替换缺失值。例如: Id Amount 1 10 2 . 3 20 4 30 5 . 6 . 7 40 期望输出 Id Amount 1 10 2 **15** 3 20 4 30 5 **35** 6 **35** 7 40 有什么建议吗?我尝试使用retain函数,但我只能找出如何保留最后一个未丢失的值。此方法有效: data have; input id amount;
Id Amount
1 10
2 .
3 20
4 30
5 .
6 .
7 40
期望输出
Id Amount
1 10
2 **15**
3 20
4 30
5 **35**
6 **35**
7 40
有什么建议吗?我尝试使用retain函数,但我只能找出如何保留最后一个未丢失的值。此方法有效:
data have;
input id amount;
cards;
1 10
2 .
3 20
4 30
5 .
6 .
7 40
;
run;
proc sort data=have out=reversed;
by descending id;
run;
data retain_non_missing;
set reversed;
retain next_non_missing;
if amount ne . then next_non_missing = amount;
run;
proc sort data=retain_non_missing out=ordered;
by id;
run;
data final;
set ordered;
retain last_non_missing;
if amount ne . then last_non_missing = amount;
if amount = . then amount = (last_non_missing + next_non_missing) / 2;
run;
但和以往一样,将需要额外的错误检查等生产使用
关键思想是将数据按相反顺序排序,允许它使用RETAIN
来携带next\u non\u missing
值备份数据集。当重新排序到正确的顺序时,您就有足够的信息来插值缺少的值
很可能会有一个PROC
以更可控的方式来实现这一点(我不知道Reeza评论中提到的PROC Standardized
),但这是一个数据步解决方案 这是有效的:
data have;
input id amount;
cards;
1 10
2 .
3 20
4 30
5 .
6 .
7 40
;
run;
proc sort data=have out=reversed;
by descending id;
run;
data retain_non_missing;
set reversed;
retain next_non_missing;
if amount ne . then next_non_missing = amount;
run;
proc sort data=retain_non_missing out=ordered;
by id;
run;
data final;
set ordered;
retain last_non_missing;
if amount ne . then last_non_missing = amount;
if amount = . then amount = (last_non_missing + next_non_missing) / 2;
run;
但和以往一样,将需要额外的错误检查等生产使用
关键思想是将数据按相反顺序排序,允许它使用RETAIN
来携带next\u non\u missing
值备份数据集。当重新排序到正确的顺序时,您就有足够的信息来插值缺少的值
很可能会有一个
PROC
以更可控的方式来实现这一点(我不知道Reeza评论中提到的PROC Standardized
),但这是一个数据步解决方案 这里有一个不需要排序的替代方案。它确实要求ID是连续的,但如果它们不是连续的,也可以解决这个问题
它所做的是使用两个set
语句,一个获取主(和前一个)金额,另一个设置直到找到下一个金额。在这里,我使用id
变量序列来保证它是正确的记录,但是如果id变量不是顺序的或者没有任何排序的顺序,如果需要,您可以用不同的方式编写它(跟踪您在哪个循环上)
我使用first.amount
检查以确保执行第二个set
语句的次数不会超过应该执行的次数(这会提前终止)
如果要对第一行/最后一行进行不同的处理,需要做两件事。在这里,如果是第一行,我假设上一个金额为0,并且我假设最后一个金额缺失,这意味着最后一行只是重复上一个金额,而第一行是0和下一个金额之间的平均值。如果你愿意的话,你可以对其中任何一个区别对待,我不知道你的数据
data have;
input Id Amount;
datalines;
1 10
2 .
3 20
4 30
5 .
6 .
7 40
;;;;
run;
data want;
set have;
by amount notsorted; *so we can tell if we have consecutive missings;
retain prev_amount; *next_amount is auto-retained;
if not missing(amount ) then prev_amount=amount;
else if _n_=1 then prev_amount=0; *or whatever you want to treat the first row as;
else if first.amount then do;
do until ((next_id > id and not missing(next_amount)) or (eof));
set have(rename=(id=next_id amount=next_amount)) end=eof;
end;
amount = mean(prev_amount,next_amount);
end;
else amount = mean(prev_amount,next_amount);
run;
这里有一个不需要排序的替代方案。它确实要求ID是连续的,但如果它们不是连续的,也可以解决这个问题 它所做的是使用两个
set
语句,一个获取主(和前一个)金额,另一个设置直到找到下一个金额。在这里,我使用id
变量序列来保证它是正确的记录,但是如果id变量不是顺序的或者没有任何排序的顺序,如果需要,您可以用不同的方式编写它(跟踪您在哪个循环上)
我使用first.amount
检查以确保执行第二个set
语句的次数不会超过应该执行的次数(这会提前终止)
如果要对第一行/最后一行进行不同的处理,需要做两件事。在这里,如果是第一行,我假设上一个金额为0,并且我假设最后一个金额缺失,这意味着最后一行只是重复上一个金额,而第一行是0和下一个金额之间的平均值。如果你愿意的话,你可以对其中任何一个区别对待,我不知道你的数据
data have;
input Id Amount;
datalines;
1 10
2 .
3 20
4 30
5 .
6 .
7 40
;;;;
run;
data want;
set have;
by amount notsorted; *so we can tell if we have consecutive missings;
retain prev_amount; *next_amount is auto-retained;
if not missing(amount ) then prev_amount=amount;
else if _n_=1 then prev_amount=0; *or whatever you want to treat the first row as;
else if first.amount then do;
do until ((next_id > id and not missing(next_amount)) or (eof));
set have(rename=(id=next_id amount=next_amount)) end=eof;
end;
amount = mean(prev_amount,next_amount);
end;
else amount = mean(prev_amount,next_amount);
run;
我想你要找的可能更像插值。虽然这不是两个最接近值的平均值,但它可能有用 有一个漂亮的小工具用于在数据集中进行插值,名为proc expand。(它也可以做外推,但我还没有尝试过。)它在进行一系列日期和累积计算时非常方便
data have;
input Id Amount;
datalines;
1 10
2 .
3 20
4 30
5 .
6 .
7 40
;
run;
proc expand data=have out=Expanded;
convert amount=amount_expanded / method=join;
id id; /*second is column name */
run;
有关proc expand的更多信息,请参阅文档:我认为您所寻找的可能更像插值。虽然这不是两个最接近值的平均值,但它可能有用 有一个漂亮的小工具用于在数据集中进行插值,名为proc expand。(它也可以做外推,但我还没有尝试过。)它在进行一系列日期和累积计算时非常方便
data have;
input Id Amount;
datalines;
1 10
2 .
3 20
4 30
5 .
6 .
7 40
;
run;
proc expand data=have out=Expanded;
convert amount=amount_expanded / method=join;
id id; /*second is column name */
run;
有关proc expand的更多信息,请参阅文档:如何定义最近的?对于记录5,为什么不是25的20/30?你的规则需要澄清。有关替换缺失值的选项,请参阅PROC标准化和缺失选项。如果你的案例真的像你的样本,那么缺失值的线性回归可能是另一种选择。为了澄清,就“接近”而言,我想要上一个非缺失值和下一个非缺失值。您如何定义最近值?对于记录5,为什么不是25的20/30?你的规则需要澄清。有关替换缺失值的选项,请参阅PROC标准化和缺失选项。如果你的案例真的像你的样本,那么缺失值的线性回归可能是另一种选择。为了澄清,就“接近”而言,我想要上一个非缺失值和下一个非缺失值nice,这是可行的。我注意到的唯一一点是,如果第一个或最后一个观察值丢失,那么代码将不会填充这些观察值(b/c没有最后一个未丢失或下一个未丢失)。但这是一个小问题,你可以手工填写。太好了,如果你满意的话,请将此标记为正确答案。关于缺少第一个/最后一个值,您是对的,这就是为什么我强调需要额外的错误检查-您最初的问题没有指定在这些情况下要做什么,所以我什么也没做。也许你只想带上最后一个已知的值