楼主: Rock2000
515 9

[有偿编程] 怎样计算列变量两组对象间时间差 [推广有奖]

  • 0关注
  • 23粉丝

院士

75%

还不是VIP/贵宾

-

威望
1
论坛币
105342 个
学术水平
43 点
热心指数
62 点
信用等级
36 点
经验
23059 点
帖子
504
精华
0
在线时间
7971 小时
注册时间
2004-5-27
最后登录
2018-7-19

Rock2000 发表于 2018-4-16 16:26:27 |显示全部楼层
100论坛币
有一批数据,格式如下

  1. name  date       group
  2. 白云        2016/12/11  1
  3. 白云        2017/10/25  1
  4. 白云        2017/6/12          2
  5. 白云        2017/12/25        2
  6. 白云        2017/11/22        2
  7. 白云        2016/9/20          2
  8. 白云        2016/8/10          2
  9. 鲍宝芝 2017/10/15 1
  10. 鲍宝芝        2017/7/2        1
  11. 鲍宝芝        2017/8/11        2
  12. 毕蕾        2016/8/26   1
  13. 毕蕾        2016/12/23  2
  14. 毕蕾        2016/10/21  2
复制代码
现在想计算:name相同的记录,group=1的(可能有2个以上)与group=2的date之周数差,其差值分别生成week1、week2...(按照group总数减1),怎样编程?谢谢。

最佳答案

Tigflanker 查看完整内容

和你的结果compare了一下,totally match
关键词:时间差 Group name Week date

回帖推荐

Tigflanker 发表于5楼  查看完整内容

没很看明白最终需求,我写了个大概,或者给个例子?

Tigflanker 发表于8楼  查看完整内容

和你的结果compare了一下,totally match
stata SPSS
Tigflanker 发表于 2018-4-16 16:26:28 |显示全部楼层
Rock2000 发表于 2018-4-18 18:17
其实我有很笨方法如下:
  1. data test;
  2. input name $ date:yymmdd10.  mark;
  3. format date yymmdd10.;
  4. cards;
  5. 白云      2016/12/11  1
  6. 白云      2017/10/25  1
  7. 白云      2017/6/12   2
  8. 白云      2017/12/25  2
  9. 白云      2017/11/22  2
  10. 白云      2016/9/20   2
  11. 白云      2016/8/10   2
  12. 鲍宝芝    2017/10/15  1
  13. 鲍宝芝    2017/7/2    1
  14. 鲍宝芝    2017/8/11   2
  15. 毕蕾      2016/8/26   1
  16. 毕蕾      2016/12/23  2
  17. 毕蕾      2016/10/21  2
  18. 张三        2016/8/26   1
  19. 张三        2016/9/23  1
  20. 张三        2016/10/21  1
  21. 张三        2016/12/26  1
  22. 张三        2017/12/23  2
  23. 张三        2017/10/21  2
  24. ;
  25. run;

  26. data tmp1;
  27.   set test;
  28.   by name mark;

  29.   retain grp 1;
  30.   grp = ifn(first.mark,1,grp + 1);

  31.   sid = _n_;
  32. run;

  33. proc sql;
  34.   create table tmp2 as
  35.   select a.name, a.date as date_g1, b.date as date_g2, a.sid as sid1, b.sid as sid2, intck('day', a.date, b.date) as weeks
  36.   from tmp1 a full join tmp1 b
  37.   on a.name = b.name
  38.   where a.mark = 1 and b.mark = 2
  39.   order by name, sid2, sid1, date_g1;
  40. quit;

  41. proc transpose data = tmp2 out = tmp_sub prefix= week;
  42.   by name sid2;
  43.   var weeks;
  44. quit;

  45. proc sql;
  46.   create table final(drop = _:) as
  47.   select a.name, a.date, a.mark, a.sid, a.grp, b.*
  48.   from tmp1 a left join tmp_sub(rename=(name = _name sid2 = _sid)) b
  49.   on a.name = b._name and a.sid = b._sid
  50.   ;
  51. quit;
复制代码
和你的结果compare了一下,totally match
已有 1 人评分学术水平 热心指数 信用等级 收起 理由
Rock2000 + 5 + 5 + 1 精彩帖子

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

回复

使用道具 举报

Rock2000 发表于 2018-4-17 16:54:48 |显示全部楼层
哪位帮忙想想?如果不能发帖,可以私聊我,谢谢。
回复

使用道具 举报

paperaeroplane 发表于 2018-4-18 13:40:59 |显示全部楼层
本帖最后由 paperaeroplane 于 2018-4-18 14:08 编辑

编辑掉,来跟大神学习下
回复

使用道具 举报

Tigflanker 发表于 2018-4-18 14:37:52 |显示全部楼层
本帖最后由 Tigflanker 于 2018-4-18 14:39 编辑
  1. data have(drop = mass);
  2.   input mass $50.;
  3.   name = scan(mass,1,' ');
  4.   format date yymmdd10.;
  5.   date = input(scan(mass,2,' '),yymmdd10.);
  6.   group = input(scan(mass,3,' '),best.);
  7. cards;
  8. 白云        2016/12/11  1
  9. 白云        2017/10/25  1
  10. 白云        2017/6/12          2
  11. 白云        2017/12/25        2
  12. 白云        2017/11/22        2
  13. 白云        2016/9/20          2
  14. 白云        2016/8/10          2
  15. 鲍宝芝 2017/10/15 1
  16. 鲍宝芝        2017/7/2        1
  17. 鲍宝芝        2017/8/11        2
  18. 毕蕾        2016/8/26   1
  19. 毕蕾        2016/12/23  2
  20. 毕蕾        2016/10/21  2
  21. ;run;

  22. proc sort data = have;
  23.   by name group date;
  24. quit;

  25. proc sql;
  26.   create table tmp as
  27.   select a.name, a.date as date_g1, b.date as date_g2, intck('week', a.date, b.date) as weeks
  28.   from have a full join have b
  29.   on a.name = b.name
  30.   where a.group = 1 and b.group = 2;
  31. quit;

  32. proc transpose data = tmp out = tmp2 prefix= week;
  33.   by name date_g1;
  34.   var weeks;
  35. quit;
复制代码
没很看明白最终需求,我写了个大概,或者给个例子?
回复

使用道具 举报

Rock2000 发表于 2018-4-18 18:09:34 |显示全部楼层
Tigflanker 发表于 2018-4-18 14:37
没很看明白最终需求,我写了个大概,或者给个例子?
其实我需要的结果是这样
Obsnamedatemarksidgrpweek1week2week3week4
1白云2016-12-11111....
2白云2017-10-25122....
3白云2017-06-12231183-135..
4白云2017-12-2524237961..
5白云2017-11-2225334628..
6白云2016-09-20264-82-400..
7白云2016-08-10275-123-441..
8鲍宝芝2017-10-15181....
9鲍宝芝2017-07-02192....
10鲍宝芝2017-08-112101-6540..
11毕蕾2016-08-261111....
12毕蕾2016-12-232121119...
13毕蕾2016-10-21213256...
14张三2016-08-261141....
15张三2016-09-231152....
16张三2016-10-211163....
17张三2016-12-261174....
18张三2017-12-232181484456428362
19张三2017-10-212192421393365299

比如name=白云mark=1有两条记录,我需要的是name=白云mark=2的其它记录的date分别于mark=1进行计算,我上面结果week1就是mark=2与mark=1第一条分别记录计算的差,week2就是mark=2与mark=1第二条分别记录计算时间差。

回复

使用道具 举报

Rock2000 发表于 2018-4-18 18:17:30 |显示全部楼层
其实我有很笨方法如下:
  1. data test;
  2. input name $ date:yymmdd10.  mark;
  3. format date yymmdd10.;
  4. cards;
  5. 白云      2016/12/11  1
  6. 白云      2017/10/25  1
  7. 白云      2017/6/12   2
  8. 白云      2017/12/25  2
  9. 白云      2017/11/22  2
  10. 白云      2016/9/20   2
  11. 白云      2016/8/10   2
  12. 鲍宝芝    2017/10/15  1
  13. 鲍宝芝    2017/7/2    1
  14. 鲍宝芝    2017/8/11   2
  15. 毕蕾      2016/8/26   1
  16. 毕蕾      2016/12/23  2
  17. 毕蕾      2016/10/21  2
  18. 张三        2016/8/26   1
  19. 张三        2016/9/23  1
  20. 张三        2016/10/21  1
  21. 张三        2016/12/26  1
  22. 张三        2017/12/23  2
  23. 张三        2017/10/21  2
  24. ;
  25. run;

  26. data test; set test;
  27. retain sid 0;
  28. sid=sid+1;
  29. run;

  30. data a; set test; if mark=1; run;

  31. proc sort data=a; by name; run;

  32. data dups nodups;
  33. set a;
  34. by name;
  35. if first.name and last.name then output nodups;
  36. else output dups;
  37. run;

  38. data nodups; set nodups; grp=1; run;

  39. proc sort data=dups; by name; run;

  40. data dups; set dups; /*对mark=1的记录重新赋于顺序号grp*/
  41. by name;
  42. retain grp 0;
  43. if first.name then grp=1;
  44. else grp=grp+1;
  45. run;

  46. data b; set test; if mark=2;run;

  47. proc sort data=b; by name; run;

  48. data b; set b; /*对mark=2的记录重新赋于顺序号grp*/
  49. by name;
  50. retain grp 0;
  51. if first.name then grp=1;
  52. else grp=grp+1;
  53. run;

  54. data c; set dups nodups; run;

  55. data c2; set c; if grp=2; run;
  56. data c3; set c; if grp=3; run;
  57. data c4; set c; if grp=4; run; /*因为mark=1有4个重名的*/

  58. data d; set b c; run; /*再次合并mark=1 及mark=2*/

  59. data e1; set d; if (mark=1 and grp=1) or mark=2; run;

  60. data e2; set d;             /*不能像e1一样取得数据,需要按照C2来取得数据,痛苦*/
  61. if name="白云" or name="鲍宝芝" or name="张三";
  62. if mark=1 and grp^=2 then delete;
  63. run;

  64. data e3; set d;
  65. if name="张三";
  66. if mark=1 and grp^=3 then delete;
  67. run;

  68. data e4; set d;  /*如果mark=1有很多就晕了*/
  69. if name="张三";
  70. if mark=1 and grp^=4 then delete;
  71. run;

  72. proc sort data=e1; by name mark; run; /*恢复原顺序*/
  73. proc sort data=e2; by name mark; run;
  74. proc sort data=e3; by name mark; run;
  75. proc sort data=e4; by name mark; run;

  76. data e1; set e1;
  77. by name mark;   
  78. week=dif1(date);
  79. week2=dif2(date);
  80. week3=dif3(date);
  81. week4=dif4(date);
  82. week5=dif5(date); /*mark=2总共有5个重名*/
  83. if grp=2 then week=week2;
  84. if grp=3 then week=week3;
  85. if grp=4 then week=week4;
  86. if grp=5 then week=week5;
  87. if first.name then week=.;
  88. drop week2--week5;
  89. run;

  90. data e2; set e2;
  91. by name mark;   
  92. week=dif1(date);
  93. week2=dif2(date);
  94. week3=dif3(date);
  95. week4=dif4(date);
  96. week5=dif5(date); /*mark=2总共有5个重名*/
  97. if grp=2 then week=week2;
  98. if grp=3 then week=week3;
  99. if grp=4 then week=week4;
  100. if grp=5 then week=week5;
  101. if first.name then week=.;
  102. drop week2--week5;
  103. run;

  104. data e3; set e3;
  105. by name mark;   
  106. week=dif1(date);
  107. week2=dif2(date);
  108. week3=dif3(date);
  109. week4=dif4(date);
  110. week5=dif5(date); /*mark=2总共有5个重名*/
  111. if grp=2 then week=week2;
  112. if grp=3 then week=week3;
  113. if grp=4 then week=week4;
  114. if grp=5 then week=week5;
  115. if first.name then week=.;
  116. drop week2--week5;
  117. run;

  118. data e4; set e4;
  119. by name mark;   
  120. week=dif1(date);
  121. week2=dif2(date);
  122. week3=dif3(date);
  123. week4=dif4(date);
  124. week5=dif5(date); /*mark=2总共有5个重名*/
  125. if grp=2 then week=week2;
  126. if grp=3 then week=week3;
  127. if grp=4 then week=week4;
  128. if grp=5 then week=week5;
  129. if first.name then week=.;
  130. drop week2--week5;
  131. run;

  132. proc datasets library=work; modify e1; rename week=week1; run;
  133. proc datasets library=work; modify e2; rename week=week2; run;
  134. proc datasets library=work; modify e3; rename week=week3; run;
  135. proc datasets library=work; modify e4; rename week=week4; run;

  136. proc sort data=e1; by sid; run;
  137. proc sort data=e2; by sid; run;
  138. proc sort data=e3; by sid; run;
  139. proc sort data=e4; by sid; run;

  140. data f; merge e1 e2 e3 e4;
  141. by sid;
  142. run;

  143. proc print data=f; run;
复制代码


回复

使用道具 举报

Rock2000 发表于 2018-4-18 18:35:48 |显示全部楼层
Tigflanker 发表于 2018-4-18 14:37
没很看明白最终需求,我写了个大概,或者给个例子?
想得到的结果如下:

Obsnamedatemarksidgrpweek1week2week3week4
1白云2016-12-11111....
2白云2017-10-25122....
3白云2017-06-12231183-135..
4白云2017-12-2524237961..
5白云2017-11-2225334628..
6白云2016-09-20264-82-400..
7白云2016-08-10275-123-441..
8鲍宝芝2017-10-15181....
9鲍宝芝2017-07-02192....
10鲍宝芝2017-08-112101-6540..
11毕蕾2016-08-261111....
12毕蕾2016-12-232121119...
13毕蕾2016-10-21213256...
14张三2016-08-261141....
15张三2016-09-231152....
16张三2016-10-211163....
17张三2016-12-261174....
18张三2017-12-232181484456428362
19张三2017-10-212192421393365299




比如,name=白云mark=1有2条记录,mark=2有5条记录,现在用mark=2与mark=1的两条记录分别计算时间差,结果中,week1就是mark=2分别与mark=1的第一条记录计算的结果,week2就是mark=2分别与mark=1的第二条记录计算的结果。


回复

使用道具 举报

Tigflanker 发表于 2018-4-18 19:51:43 |显示全部楼层
Rock2000 发表于 2018-4-18 18:17
其实我有很笨方法如下:
另外,如果您实在着急写句子:
  1. proc sort data=e1; by name mark; run; /*恢复原顺序*/
  2. proc sort data=e2; by name mark; run;

  3. data e1; set e1;
  4. by name mark;   
  5. week=dif1(date);
  6. week2=dif2(date);
  7. week3=dif3(date);
  8. week4=dif4(date);
  9. week5=dif5(date); /*mark=2总共有5个重名*/
  10. if grp=2 then week=week2;
  11. if grp=3 then week=week3;
  12. if grp=4 then week=week4;
  13. if grp=5 then week=week5;
  14. if first.name then week=.;
  15. drop week2--week5;
  16. run;

  17. data e2; set e2;
  18. by name mark;   
  19. week=dif1(date);
  20. week2=dif2(date);
  21. week3=dif3(date);
  22. week4=dif4(date);
  23. week5=dif5(date); /*mark=2总共有5个重名*/
  24. if grp=2 then week=week2;
  25. if grp=3 then week=week3;
  26. if grp=4 then week=week4;
  27. if grp=5 then week=week5;
  28. if first.name then week=.;
  29. drop week2--week5;
  30. run;
复制代码
等价于:
  1. %macro temp:

  2. *Something else;

  3. %do i = 1 %to 2;
  4.   proc sort data=e&i.; by name mark; run;
  5. %end;

  6. %do i = 1 %to 2;
  7.   data e&i.; set e&i.;
  8.   by name mark;   
  9.   week=dif1(date);
  10.   week2=dif2(date);
  11.   week3=dif3(date);
  12.   week4=dif4(date);
  13.   week5=dif5(date); /*mark=2总共有5个重名*/
  14.   if grp=2 then week=week2;
  15.   if grp=3 then week=week3;
  16.   if grp=4 then week=week4;
  17.   if grp=5 then week=week5;
  18.   if first.name then week=.;
  19.   drop week2--week5;
  20.   run;
  21. %end;

  22. *Something else;

  23. %mend;

  24. %temp;
复制代码
也可以用一些宏来简化书写
回复

使用道具 举报

Rock2000 发表于 2018-4-19 00:00:48 |显示全部楼层
谢谢@Tigflanker
回复

使用道具 举报

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

GMT+8, 2018-7-19 13:37