楼主: playmore
8063 9

请问如何滚动计算自某一指定起始日至今的平均值和标准差 [推广有奖]

已卖:1645份资源

学科带头人

2%

还不是VIP/贵宾

-

TA的文库  其他...

R相关

经济学相关

金融工程

威望
1
论坛币
16356 个
通用积分
8.6697
学术水平
372 点
热心指数
394 点
信用等级
341 点
经验
15297 点
帖子
1194
精华
1
在线时间
1332 小时
注册时间
2007-1-11
最后登录
2025-12-1

初级学术勋章 初级热心勋章 中级热心勋章

楼主
playmore 发表于 2014-4-11 17:41:25 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
我现在有如下的表格

data have;
input id $ num;
datalines;
a 1
a 2
a 4
a 3
b 2
b 3
b 9
;
run;

每个id的数据都是按日期排好序的,为方便就不列日期了。我要得到的是每个id,自初始第一个观测开始至当前观测的平均值和标准差,即得到如下的结果:

id   num   mean                              std
a    1          1                               #DIV/0!
a    2          1.5                            0.707106781
a    4          2.333333333            1.527525232
a    3          2.5                            1.290994449
b    2          2                              #DIV/0!
b    3          2.5                           0.707106781
b    9          4.666666667           3.785938897

首先,我想过用array来做,但是因为这里的需要计算的数会逐渐增加,而且我的表格的观测数量很大,用array可能会比较耗时间。

另外,好像也不能用retain来做。只求平均值的话,用retain计算累积值再平均还比较方便,但是求标准差的话,估计就麻烦了。

现在想来用R的话会很方便,但是还是想用SAS实现下。现在想得头都大了,所以请教版上高人了,多谢!
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:滚动计算 平均值 标准差 RETAIN array 标准差 平均值 如何

本帖被以下文库推荐

playmore邀请您访问ChinaTeX论坛!!!进入ChinaTeX论坛

沙发
zhengbo8 发表于 2014-4-11 19:31:50
关于标准差计算可使用简化公式。


  1. data have;
  2. input id $ num;
  3. datalines;
  4. a 1
  5. a 2
  6. a 4
  7. a 3
  8. b 2
  9. b 3
  10. b 9
  11. ;

  12. data have(drop=num2 sum1 sum2 pre);
  13.         
  14.         set have;
  15.         num2=num*num;

  16.         retain sum1 sum2 pre 0 ;
  17.                
  18.         if (lag(id)^=id) then do;
  19.               sum1=0;
  20.               sum2=0;
  21.               pre=_n_-1;
  22.         end;
  23.         
  24.         sum1=sum1+num;
  25.         sum2=sum2+num2;

  26.         if (lag(id)^=id) then mean=sum1;
  27.         else mean=sum1/(_n_-pre);

  28.         if ((lag(id)=id) & (_n_>1)) then do;
  29.              std=sqrt((sum2-sum1*sum1/(_n_-pre))/(_n_-pre-1));
  30.         end;
  31.         
  32. run;
复制代码


2014-04-12_000314.gif
已有 2 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
playmore + 5 + 5 + 5 观点有启发
admin_kefu + 100 热心帮助其他会员

总评分: 论坛币 + 100  学术水平 + 5  热心指数 + 5  信用等级 + 5   查看全部评分

藤椅
yongyitian 发表于 2014-4-11 23:03:28
Using PROC SQL for calculating Moving average, std

  1. data have;
  2. input id $ num date yymmdd8.;
  3. format date yymmdd10.;
  4. datalines;
  5. a 1 20140101
  6. a 2 20140102
  7. a 4 20140103
  8. a 3 20140104
  9. b 2 20140105
  10. b 3 20140106
  11. b 9 20140107
  12. ; run;

  13. proc sql;
  14.     create table SQL_moving as
  15.      select distinct a.id, a.date, a.num,
  16.                    sum(b.num) as num_sum,
  17.                    avg(b.num) as num_mean,
  18.                    std(b.num) as num_std
  19.      from have as a, have as b
  20.      where a.id=b.id and (a.date - b.date >=0 )
  21.      group by a.id, a.date;
  22. quit;

  23. proc print data=SQL_moving; title 'SQL_moving'; run; title;
复制代码



SQL_moving.JPG
已有 1 人评分学术水平 热心指数 信用等级 收起 理由
playmore + 5 + 5 + 5 精彩帖子

总评分: 学术水平 + 5  热心指数 + 5  信用等级 + 5   查看全部评分

板凳
bobguy 发表于 2014-4-12 10:36:16
There are a couple of ways.

One is to use a recursive formula. Here is wikipedia link

http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance

The other is to use SAS function. Either way one pass is enough.

data have;
input id $ num;
datalines;
a 1
a 2
a 4
a 3
b 2
b 3
b 9
;


data need;
  set have;
  by id;
  array tmp[10000] _temporary_;
  if first.id then n=0 ;
  n+1;
  tmp[n]=num;
  mean=mean(of tmp(*));
  std =std(of tmp(*));
  if last.id then do;
     do i=1 to n;
       tmp=.;
     end;
  end;
  drop n i;
  run;

  proc print;run;

报纸
bobguy 发表于 2014-4-12 10:44:26
bobguy 发表于 2014-4-12 10:36
There are a couple of ways.

One is to use a recursive formula. Here is wikipedia link
Here is a more concise solution.

data need;
  set have;
  by id;
  array tmp[10000] _temporary_;
  if first.id then n=0 ;
  n+1;
  tmp[n]=num;
  mean=mean(of tmp(*));
  std =std(of tmp(*));
  if last.id then call missing (of tmp(*));
  drop n ;
  run;

  proc print;run;

地板
playmore 发表于 2014-4-14 13:26:54
zhengbo8 发表于 2014-4-11 19:31
关于标准差计算可使用简化公式。
多谢

用这个公式就没我之前的问题了,当时对着$\sum{(x_i-\bar{x})^2}$看了半天,竟然忘了还有这公式了
playmore邀请您访问ChinaTeX论坛!!!进入ChinaTeX论坛

7
playmore 发表于 2014-4-14 13:34:39
yongyitian 发表于 2014-4-11 23:03
Using PROC SQL for calculating Moving average, std
多谢,这个SQL的办法也好,
只不过用到了笛卡尔积,速度比其他方法慢一些
playmore邀请您访问ChinaTeX论坛!!!进入ChinaTeX论坛

8
playmore 发表于 2014-4-14 13:50:52
bobguy 发表于 2014-4-12 10:44
Here is a more concise solution.

data need;
多谢bobguy

你这里的方法就是我之前想到的,也是我用在我的GetMovingStats宏里的方法

我这个宏用于计算滚动均值、标准差、下标准差、最大回撤、相关系数之类的,写得比较复杂,也没什么条理,光一个宏文件就用了20几k

里面用的方法就是用临时数组保存之前一定时间窗口内的数据,然后对临时数组进行计算,因为时间窗口固定,所以临时数组的大小也固定,在定义临时数组的时候指定就好了

这回的问题是变动的临时数组,光设置为tmp[10000]害怕不够robust,但是我试了下
array tmp[ 星号 ] _temporary_ 会报错,后来我又试了下把10000改为1000000(百万量级而已,平时我的数据集基本上都是这个量级),然后SAS直接死了,过了好长一阵报出如下错误:
ERROR: The SAS System stopped processing this step because of insufficient memory.
这是我第一次遇到这种错误,我觉得临时数组应该是保存在内存,而数据集是在硬盘,所以不能拿临时数据来做这件事了
playmore邀请您访问ChinaTeX论坛!!!进入ChinaTeX论坛

9
playmore 发表于 2014-4-14 14:00:56
多谢ls各位回复
坛子里就是牛人多


playmore邀请您访问ChinaTeX论坛!!!进入ChinaTeX论坛

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2026-1-6 10:11