楼主: fantastli
3088 12

[问答] 新手求教,如何实现以下数据处理,急 [推广有奖]

  • 0关注
  • 0粉丝

高中生

7%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
196 点
帖子
18
精华
0
在线时间
12 小时
注册时间
2010-1-7
最后登录
2011-5-11

楼主
fantastli 发表于 2011-4-13 12:21:42 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

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

经管之家联合CDA

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

感谢您参与论坛问题回答

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

+2 论坛币
刚刚接触SAS不到3个月,还有很多不懂的地方。最近在做一个课程的小project,编程思路上被卡住了,希望高人能够指点以下。
因为只知道数据可以横向处理,像这种带条件的,不规则的,还是纵向处理数据的project还是第一次碰到。

比如我有数据如下:

公司            日期1(D1)      日期2(D2)             金额A (PA)      金额B(PB)
A               2001.03.01       2001.03.30               100                150
A               2001.03.06       2001.03.30               100                120
A               2001.03.29       2001.03.30               100                90
A               2001.04.01       2001.04.30                200               160
A               2001.04.15       2001.04.30                200               180
A               2001.04.20       2001.04.30                200               190      
A               2001.04.28       2001.04.30                200               180
B               2001.03.01       2001.03.30               105                112
B               2001.03.08       2001.03.30               105                110
B               2001.03.28       2001.03.30               105                60
B               2001.04.05       2001.04.30               100                90
B               2001.04.16       2001.04.30               100                80
B               2001.04.27       2001.04.30               100               105      
B               2001.04.28       2001.04.30               100               110
B               2001.04.29       2001.04.30               100               110

现在,打算实现如下运算。
计算1:
以“日期2”为基准,如果“日期1”是在“日期2”之前的30天之内,则把这些“日期1”所对应的“金额B”取平均值,得到“基数A”,之后用“金额A”减去“基数A”。

计算2:
以“日期2”为基准,取“日期1”中距离“日期2”最近的一天,把该“日期1”所对应的“金额B”作为“基数B”,之后用“金额A”减去“基数B”。

因为有不同的公司,每个公司又有不同年份和月份,所以总共有将近300万个数据。
要求把结果按照公司和年份分类,观察得到的差值变化。
想了3天,到现在没有任何思路。
二维码

扫码加我 拉你入群

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

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

关键词:如何实现 新手求教 数据处理 Project 处理数据 数据处理 新手 求教 数据分析专题 数据处理 数据分析软件 数据分析报告 面板数据分析 excel数据分析 数据分析方法 项目数据分析

回帖推荐

275769263 发表于6楼  查看完整内容

由于你的数据量大,建议你使用hash。 data sample1; input co$ 1. date1 yymmdd11. date2 yymmdd11. pa pb; cards; A 2001-03-01 2001-03-30 100 150 A 2001-03-06 2001-03-30 100 120 A 2001-03-29 2001-03-30 100 90 A 2001-04-01 2001-04-30 200 160 A 2001-04-15 2001-04-30 200 180 A 2001-04-20 2001-04-30 200 190 A 2001-04-28 2001-04-30 200 180 B 2001-03-01 2001-03-30 105 112 B 2001-03-08 20 ...

本帖被以下文库推荐

沙发
dankdark 发表于 2011-4-13 13:49:27
try to use
proc sql;
group by 公司,      日期2(D2)

藤椅
myc_sas 发表于 2011-4-13 18:26:08
这两个计算都是要先按公司和年份划分吗?

比如,计算1,如果只有你给的这15条数据,7条A公司8条B公司,所有数据都是符合你的D2 - D1 <=30的条件的。那么计算基数A的时候,是15个金额取平均呢,还是对A公司的7条取平均,对B公司的8条取平均?

年份也是类似,比如,如果有A公司有20条数据符合D2-D1<=30,其中8条是2001年的,12条是2002年的,算基数A需要根据年份分开么?

板凳
fantastli 发表于 2011-4-13 22:11:00
3# myc_sas
你好,是的,年份和公司都要分开取
也就是说A公司2001年3月和4月要分开取平均值
B公司也同样。

报纸
fantastli 发表于 2011-4-13 22:35:44
我昨天想破头,编了下面这个程序,目前只能实现一半我需要的功能。实际上,我想要得到的平均值,就是以不同的公司和“日期2”来划分的。

之前先数据处理,同一家公司,D1-D2范围大于30天的数据,进行删除。其中公司是用代码来表示的,比如公司1和公司2。

然后进行如下操作

data test;
set dansas.test;
dummy_date+0;
dummy_company+0;  /* Initial dummy value is zero*/

do i=1 to 1;
if company=dummy_company and d2=dummy_date then
do j=1 to 1;
total_p2+p2;
no+1;
mean_p2=total_p2/no;
end;
else
do k=1 to 1;
total_p2=0;
no=1;
dummy_date=d2;
dummy_company=company;
total_p2=p2;
mean_p2=total_p2/no;
end;
end;
run;

proc print data=test;
var  dummy_date dummy_company p2 total_p2 mean_p2;
run;

结果会得到如下运行结果:
公司            日期1(D1)      日期2(D2)             金额1 (P1)      金额2(P2)   个数(NO) 累加金额2(total_P2)  平均金额2(mean_p2)
1               2001.03.01       2001.03.30               100                150               1                   150                                  150
1               2001.03.06       2001.03.30               100                120               2                   270                                  135
1               2001.03.29       2001.03.30               100                90                 3                   360                                  120 (需要)
1               2001.04.01       2001.04.30                200               160               1                   160                                  160
1               2001.04.15       2001.04.30                200               180               2                   340                                  170
1               2001.04.20       2001.04.30                200               190               3                   530                                  176.7
1               2001.04.28       2001.04.30                200               180               4                   710                                  177.5(需要)
2               2001.03.01       2001.03.30               105                112               1                   112                                  112
2               2001.03.08       2001.03.30               105                110               2                   222                                  111
2               2001.03.28       2001.03.30               105                60                 3                   282                                   94  (需要)
2               2001.04.05       2001.04.30               100                90                 1                   90                                     90
2               2001.04.16       2001.04.30               100                80                 2                   170                                   85
2               2001.04.27       2001.04.30               100               105                3                   275                                   91.5
2               2001.04.28       2001.04.30               100               110                4                   385                                   96.3
2               2001.04.29       2001.04.30               100               110                5                   495                                   99(需要)


可以看出,我做的平均值实际上就是“累加金额2”除以前面的“累加个数”。但实际上,只有每个“日期2”周期内,最后一个“日期1”所对应的平均值才是真实我想要的30天内的"金额2"的平均值。
然后,我需要用“金额1”减去这个“需要”的“平均值”,在把这些数字从表格中提取出来。
现在的问题是,如何可以只把需要的那几行数字提取出来。我如果仅仅用“金额1”减去“平均值”,列在前面的几个结果,实际上是无效的。

地板
275769263 发表于 2011-4-14 08:03:03
由于你的数据量大,建议你使用hash。
data sample1;
input co$ 1.  date1 yymmdd11. date2 yymmdd11.  pa pb;
cards;
A 2001-03-01 2001-03-30 100 150
A 2001-03-06 2001-03-30 100 120
A 2001-03-29 2001-03-30 100 90
A 2001-04-01 2001-04-30 200 160
A 2001-04-15 2001-04-30 200 180
A 2001-04-20 2001-04-30 200 190      
A 2001-04-28 2001-04-30 200 180
B 2001-03-01 2001-03-30 105 112
B 2001-03-08 2001-03-30 105 110
B 2001-03-28 2001-03-30 105 60
B 2001-04-05 2001-04-30 100 90
B 2001-04-16 2001-04-30 100 80
B 2001-04-27 2001-04-30 100 105      
B 2001-04-28 2001-04-30 100 110
B 2001-04-29 2001-04-30 100 110
;
run;
data result;
length co $ 1;
/*定义部分*/
if _n_=1 then do;
        declare hash h1();
        h1.definekey('co','date2');
        h1.definedata('co','date2','count','ave','total');
        h1.definedone();
        call missing(total,ave,count);
        declare hiter iter1('h1');
end;
/*选择满足要求的记录进入哈希表并累加,计数*/
do until(last);
        set sample1 end=last;        
        if h1.find()=0 and date2-date1<30 then do;
                count+1;
                total+pb;
                h1.replace();
        end;
    if h1.find()^=0 and date2-date1<30 then do;
                total=pb;
                count=1;
                h1.add();
        end;
end;
/*遍历并计算输出*/
        rc=iter1.first();
        do while(rc=0);
                ave=total/count;
                name=pa-ave;
                output;
                rc=iter1.next();
        end;
run;
已有 1 人评分经验 论坛币 收起 理由
bakoll + 3 + 3 精彩帖子

总评分: 经验 + 3  论坛币 + 3   查看全部评分

7
275769263 发表于 2011-4-14 08:31:58
这是计算2的程序,修改一下变量名应该是可以通用的。
如果有什么不明白可以参考我上传的资料:https://bbs.pinggu.org/thread-1062169-1-1.html
data sample1;
input co$ 1.  date1 yymmdd11. date2 yymmdd11.  pa pb;
cards;
A 2001-03-01 2001-03-30 100 150
A 2001-03-06 2001-03-30 100 120
A 2001-03-29 2001-03-30 100 90
A 2001-04-01 2001-04-30 200 160
A 2001-04-15 2001-04-30 200 180
A 2001-04-20 2001-04-30 200 190      
A 2001-04-28 2001-04-30 200 180
B 2001-03-01 2001-03-30 105 112
B 2001-03-08 2001-03-30 105 110
B 2001-03-28 2001-03-30 105 60
B 2001-04-05 2001-04-30 100 90
B 2001-04-16 2001-04-30 100 80
B 2001-04-27 2001-04-30 100 105
B 2001-04-28 2001-04-30 100 110
B 2001-04-29 2001-04-30 100 110
;
run;
data _null_;
if _n_=1 then do;
        declare hash h2(hashexp:16);
        h2.definekey('co','date2');
        h2.definedata('co','date2');
        h2.definedone();
end;
        do until(last);
           set sample1 end=last;
           if h2.find()^=0 then h2.add();
        end;
        h2.output(dataset:'result2');
/*定义公司及日期2为唯一的关键字并映射到哈希表*/
run;
data result3;
length co $ 1;
if _n_=1 then do;
        declare hash h3(dataset:'sample1',hashexp:16,multidata:'y');/*把sample1全部数据映射到哈希表,感谢楼下soporaeternus提醒哈希表的溢出问题,此处暂时取最大n=16*/
        h3.definekey('co','date2');
        h3.definedata('co','date2','pa','pb');
        h3.definedone();
        call missing(co,date2,pa,pb,pa_pb);
        declare hiter iter3('h3');
end;
        do while(not last1);
        set result2 end=last1;
            if h3.find()=0 then do;/*通过查找刚才输出的result2,查找与h3表匹配的记录*/
                    h3.has_next(result:r);/*由于你的数据日期1已经升序排列,相同关键字下最后一条观测为最靠近日期2的记录,通过find_next查找并计算*/
                        if r^=0 then do;
                                h3.find_next();
                                pa_pb=pa-pb;
                                output;
                        end;
      if rc=0 then output;/*如果某个公司只有一条记录则输出*/
                end;
        end;
run;
最后由于还没碰到过这么多数据的处理,而网上说hash使用内存处理很快,若是运行出来,可否分享一下运行时间?哈哈

8
soporaeternus 发表于 2011-4-14 08:53:00
用hash的话,要预判下hash表的大小,否则会溢出的
Let them be hard, but never unjust

9
275769263 发表于 2011-4-14 09:07:35
8# soporaeternus
恩,谢谢,像上面有300万条,Hashexp:n 的n取多大比较合适?还没处理过这么大的数据所以没啥经验。

10
soporaeternus 发表于 2011-4-14 09:25:38
取决于公司+事件日的组合数量吧,我认为这个应该远小于300万的
我想这里用hash最大的好处可能是省掉了对300万数据排序的开销吧
Let them be hard, but never unjust

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

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2025-12-30 04:57