Hye伙计们,
我附上了截图,以帮助澄清我的问题:
http://i40.tinypic.com/mcrnmv.jpg
我正在尝试计算某种移动平均线和移动标准偏差。问题是我想计算实际值的变异系数(stdev / avg)。通常,这是通过计算过去5年的stdev和avg来完成的。但是有时在我的数据库中会有观察结果,我没有过去5年的信息(可能只有3,2等)。这就是为什么我想要一个能够计算avg和stdev的代码,即使整整5年都没有信息。
此外,正如您在观察中所看到的,有时候我有超过5年的信息,在这种情况下,我需要某种移动平均线,这使我能够计算过去5年的平均值和平均值。因此,如果一家公司有7年的信息,我需要某种代码来计算1997年(1991-1996),1998年(1992-1997)和1999年(1993-1998)的平均值和平均值。
由于我对sas命令不是很熟悉,所以它应该(非常非常粗略地)看起来像:
set var
if year = i then stdev=stdev(year(i-6) untill year(i-1)) and average = avg(year(i-6) untill year(i-1))
或类似的东西,我真的不知道,我会试着弄明白,但如果我自己找不到它,那就值得张贴。
谢谢!
答案 0 :(得分:3)
正确的方法是使用PROC EXPAND。
您可以使用很多选项,但您可能想要
PROC EXPAND DATA=TESTTEST OUT=MOVINGAVERAGE;
CONVERT VAL=AVG / TRANSFORMOUT=(MOVAVE 5);
RUN;
同样适用于MOVSTD。它会自动忽略缺失值,但您也可以调整该行为
答案 1 :(得分:1)
这是一种方法。希望这会有所帮助。
/* test data */
data one;
input symbol $ value date :date9.;
format date date9.;
cards;
ABP1 -0.025 18feb1997
ABP1 0.05 25feb1998
ABP1 -0.025 05mar1999
ABP1 0.06 20mar2000
ABP1 0.25 05mar2001
ABP1 0.455 07mar2002
ABP1 0.73 25feb2003
ABP1 1.01 19feb2004
ABP1 1.25 16feb2005
ABP1 1.65 09feb2006
ABP1 1.87 08feb2007
ABT 0.555 14jan1991
ABT 0.6375 14jan1992
ABT 0.73 16jan1993
;
run;
/* 5 year moving avg, stdev, cv assuming:
one obs per year from 1990 to 2010.
observations are already in the sorted order by symbol. */
%let START = 1990;
%let FINISH = 2010;
data two;
array val[%eval(&START-3):&FINISH] val1-val3 val&START-val&FINISH;
call missing(of val&START-val&FINISH);
do until (last.symbol);
set one;
by symbol;
year = year(date);
if &START<=year<=&FINISH then val[year] = value;
end;
do year = %eval(&START+2) to &FINISH;
avg5 = mean(val[year-5],val[year-4],val[year-3],val[year-2],val[year-1]);
std5 = std(val[year-5],val[year-4],val[year-3],val[year-2],val[year-1]);
cv5 = divide(std5,avg5);
if not missing(cv5) then output;
end;
keep symbol year avg5 std5 cv5;
run;
/* check */
proc print data=two;
run;
/* on lst
Obs symbol year avg5 std5 cv5
1 ABP1 1999 0.01250 0.05303 4.24264
2 ABP1 2001 0.01500 0.04637 3.09121
3 ABP1 2002 0.06200 0.11251 1.81461
4 ABP1 2003 0.15800 0.19457 1.23146
5 ABP1 2004 0.29400 0.30597 1.04071
6 ABP1 2005 0.50100 0.37786 0.75422
7 ABP1 2006 0.73900 0.40448 0.54734
8 ABP1 2007 1.01900 0.46185 0.45324
9 ABP1 2008 1.30200 0.46338 0.35590
10 ABP1 2009 1.44500 0.38726 0.26800
11 ABP1 2010 1.59000 0.31432 0.19769
12 ABT 1993 0.59625 0.05834 0.09784
13 ABT 1994 0.64083 0.08755 0.13662
14 ABT 1995 0.64083 0.08755 0.13662
15 ABT 1996 0.64083 0.08755 0.13662
16 ABT 1997 0.68375 0.06541 0.09566
*/
答案 2 :(得分:0)
我会在这里提倡proc sql以提高可读性。以Chang Chung的数据为例,您可以尝试以下方法:
/* test data */
data one;
input symbol $ value date :date9.;
format date date9.;
cards;
ABP1 -0.025 18feb1997
ABP1 0.05 25feb1998
ABP1 -0.025 05mar1999
ABP1 0.06 20mar2000
ABP1 0.25 05mar2001
ABP1 0.455 07mar2002
ABP1 0.73 25feb2003
ABP1 1.01 19feb2004
ABP1 1.25 16feb2005
ABP1 1.65 09feb2006
ABP1 1.87 08feb2007
ABT 0.555 14jan1991
ABT 0.6375 14jan1992
ABT 0.73 16jan1993
;
run;
proc sql;
create table two as
select distinct
a.symbol,
b.value,
year(a.date) as year,
b.date as date5
from
one a,
one b
where
a.symbol=b.symbol
and intck('year',b.date,a.date) between 1 and 5
order by
a.symbol,
year,
date5;
quit;
proc sql;
create table three as
select distinct
symbol,
year,
count(symbol) as n5,
avg(value) as avg5,
std(value) as std5
from
two
group by
symbol,
year;
quit;