楼主: 消散2
400 6

[技术讨论与投票] 有关双set的问题希望大佬解释一下究竟如何运作 [推广有奖]

  • 0关注
  • 0粉丝

大专生

86%

还不是VIP/贵宾

-

威望
0
论坛币
228 个
学术水平
1 点
热心指数
2 点
信用等级
1 点
经验
124 点
帖子
12
精华
0
在线时间
127 小时
注册时间
2016-3-25
最后登录
2018-12-6

消散2 发表于 2018-8-9 20:42:27 |显示全部楼层
50论坛币
我有两个问题转不过来,这是2017年pharmaSUG的一篇论文中的内容。论文中主要分析双set对比sql在merge方面,data步迭代数量更好,运行更快。但是两个set对我来说不太好理解,论文中说一共运行了12+5=17次,也就是其实每个数据集每一条只读了一次。
Q1: do while那句,为什么是不在那个范围内set数据集? 好难转过劲来
Q2:双SET时data步内部究竟是怎么运行的,是第一个数据集读一条,然后进入循环,满足了while条件后第二个数据集读一条,然后再循环吗?  那在进行while判断的时候难道不是5条都判断一下吗?  那不就是12*5次迭代了吗?


下面是程序
/**sample dataset**/
data bonus_criteria;
input low high factor @@;
cards;
0 500 0.1
501 1000 0.2
1001 2000 0.4
2001 5000 0.6
5001 10000 0.8
;
run;

data sale_amount;
input name $ salary amount @@;
cards;
Jim 500 200
Tom 1000 700
Lily 2000 1500
Saly 700 300
Gery 3500 3000
Coliy 4500 6000
Jony 5000 3000
lary 2000 300
Sam 1040 200
Jamy 5600 1200
Bob 3400 500
Salla 2600 24
;
run;

/** Use SET/SET join two datasets to derive new variable **/
proc sort data=bonus_criteria; by low high;run;
proc sort data=sale_amount; by amount;run;
data bonus;
set sale_amount ;
do while(not(low le amount le high));
set bonus_criteria ;
end;
bonus=salary*factor;
run;


最佳答案

hsubin 查看完整内容

Obs name salary amount low high factor bonus 1 Salla 2600 24 0 500 0.1 260 2 Jim 500 200 0 500 0.1 50 3 Sam 1040 200 0 500 0.1 104 4 Saly 700 300 ...
已有 1 人评分论坛币 学术水平 热心指数 信用等级 收起 理由
hsubin + 5 + 1 + 1 + 1 学习啦

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

stata SPSS
hsubin 在职认证  发表于 2018-8-9 20:42:28 |显示全部楼层

               Obs    name     salary    amount     low     high    factor    bonus

                   1    Salla     2600        24        0      500      0.1       260
                   2    Jim        500       200        0      500      0.1        50
                   3    Sam       1040       200        0      500      0.1       104
                   4    Saly       700       300        0      500      0.1        70
                   5    lary      2000       300        0      500      0.1       200
                   6    Bob       3400       500        0      500      0.1       340
                   7    Tom       1000       700      501     1000      0.2       200
                   8    Jamy      5600      1200     1001     2000      0.4      2240
                   9    Lily      2000      1500     1001     2000      0.4       800
                  10    Gery      3500      3000     2001     5000      0.6      2100
                  11    Jony      5000      3000     2001     5000      0.6      3000
                  12    Coliy     4500      6000     5001    10000      0.8      3600
谢谢楼主的精彩讲解。理解了双指针,每一步指针的位置,以及PDV initialization 就能理解这个题了,再次证明理解PDV是多么重要啊!多谢,学习了
回复

使用道具 举报

消散2 发表于 2018-8-9 22:39:29 |显示全部楼层
嗯我搞明白了,供大家参考,欢迎指正,共同进步

结论:双set不利于程序分享,并且如果存在排序问题会导致严重的错误。这个文献中的例子取的很巧,用这种方法确实可以解决以单变量排序的此类merge问题,倘若排序时by变量有两个,amount不是完全升序排列,会导致程序的错误。固然双set缩短迭代次数,缩短real time,但真实工作需谨慎,按指针输入,按条件输出,不推荐使用双set。


一、文献中的双set,PDV过程

程序如下:

/**sampledataset**/

data bonus_criteria;

input low high factor @@;

cards;

0500 0.1

5011000 0.2

10012000 0.4

20015000 0.6

500110000 0.8

;

run;


data sale_amount;

input name $ salary amount @@;

cards;

Jim500 200

Tom1000 700

Lily2000 1500

Saly700 300

Gery3500 3000

Coliy4500 6000

Jony5000 3000

lary2000 300

Sam1040 200

Jamy5600 1200

Bob3400 500

Salla2600 24

;

run;


/**Use SET/SET join two datasets to derive new variable **/

proc sort data=bonus_criteria;

by low high;

run;


proc sort data=sale_amount;

by amount;

run;


data bonus;

set sale_amount ;

do while(not(low le amount le high));

set bonus_criteria ;

end;

bonus=salary*factor;

run;


1.编译后,PDV含有6个显性变量:low high factor name salary amount. 同时这6个变量初始化值变为缺失

  

Low

  

High



Factor



Name



Salary



Amount


  

.

  

.



.



.



.



.


2.接下来系统读取sale_amount中的第一条观测,进入Do循环。

  

Name

  

Salary



Amount


  

Salla

  

2000



24


由于amount=24 ,并且此时程序没执行到sale_criteria,又因为low=. high=. 所以low le amount le high为假,所以while语句中为真,执行DO语句

3. 在语句里,第二个set语句产生另一个数据指针,该指针将指向表bonus_criteria的第一条观测

  

Low

  

High



Factor


  

0

  

500



0.1


然后执行end语句,并返回Do语句

4. 再次判断while语句,not( 0 le 24 le 500 ) 为假,跳出Do while循环,执行后面的语句bonus=salary * factor; 并output到bonus的第一条观测。

  

Name

  

Salary



Amount



Low



High



Factor



Bonus


  

Salla

  

2600



24



0



500



0.1



260



5. 返回data步开头,PDV清空sale_amount中的所有变量值,但不会清空bonus_criteria中的值,因为表bonus_criteria的指针仍然停留在第一条观测上,且程序还未执行到第二个set语句。


6. 读取sale_amount的第二条数据

  

Name

  

Salary



Amount


  

Jim

  

500



200


进入Do循环,判断while语句,由于未执行到下一个set语句,bonus_critera的所有变量不被清空,0 le 200 le 500为真, not ( 0 le 200 le 500) 为假,跳到end结束,执行bonus=salary * factor; 并output到bonus的第二条观测

  

Name

  

Salary



Amount



Low



High



Factor



Bonus


  

Salla

  

2600



24



0



500



0.1



260


  

Jim

  

500



200



0



500



0.1



50



7.跳到data步开始,读取sale_amount第三条观测…以此类推




已有 1 人评分论坛币 收起 理由
hsubin + 5 精彩帖子

总评分: 论坛币 + 5   查看全部评分

回复

使用道具 举报

消散2 发表于 2018-8-9 22:39:51 |显示全部楼层

二、文献中如果不排序产生的错误,PDV过程

程序如下(数据集产生过程不再赘述)

data bonus;

set sale_amount ;

do while(not(low le amount le high));

set bonus_criteria ;

end;

bonus=salary*factor;

run;

1.编译后,PDV含有6个显性变量:low high factor name salary amount. 同时这6个变量初始化值变为缺失

  

Low

  

High

Factor

Name

Salary

Amount

.

.

.

.

.

.

2.接下来系统读取sale_amount中的第一条观测,进入Do循环。

  

Name

  

Salary

Amount

Jim

500

200

由于amount=200 ,并且此时程序没执行到sale_criteria,又因为low=. high=. 所以low le amount le high为假,所以while语句中为真,执行DO语句

3. 在语句里,第二个set语句产生另一个数据指针,该指针将指向表bonus_criteria的第一条观测

  

Low

  

High

Factor

0

500

0.1

然后执行end语句,并返回Do语句

4. 再次判断while语句,not( 0 le 200 le 500 ) 为假,跳出Do while循环,执行后面的语句bonus=salary * factor; 并output到bonus的第一条观测。

  

Name

  

Salary

Amount

Low

High

Factor

Bonus

Jim

500

200

0

500

0.1

50

5. 返回data步开头,PDV清空sale_amount中的所有变量值,但不会清空bonus_criteria中的值,因为表bonus_criteria的指针仍然停留在第一条观测上,且程序还未执行到第二个set语句。

6. 读取sale_amount的第二条数据

  

Name

  

Salary

Amount

Tom

1000

700

进入Do循环,判断while语句,由于未执行到下一个set语句,bonus_critera的所有变量不被清空,0 le 700 le 500为假, not ( 0 le 200 le 500) 为真,执行Do语句。

7.再第二个set执行前,清空PDV中关于Bonus_criteria中的所有变量,第二指针指到bonus_criteria的第二条观测

  

Low

  

High

Factor

501

1000

0.2

执行END语句,返回Do语句

8. 判断while语句not( 501 le 700 le 1000) 为假,跳过Do循环,执行bonus=salary * factor; 并output到bonus的第二条观测。

  

Name

  

Salary

Amount

Low

High

Factor

Bonus

Jim

500

200

0

500

0.1

50

Tom

1000

700

501

1000

0.2

200

7.跳到data步开始,清空PDV中sale_amount的变量值,读取sale_amount第三条观测

  

Name

  

Salary

Amount

Lily

2000

1500

判断while语句,not( 501le 1500 le 1000) 为真,执行Do语句,清空PDV中bonus_criteria的变量值,读取bonus_criteria的第三条观测

  

Low

  

High

Factor

1001

2000

0.4

执行END语句,返回Do语句,判断while语句 not( 1001 le 1500 le 2000)为假,跳过Do语句,执行bonus=salary * factor; 并output到bonus的三条观测。

  

Name

  

Salary

Amount

Low

High

Factor

Bonus

Jim

500

200

0

500

0.1

50

Tom

1000

700

501

1000

0.2

200

Lily

2000

1500

1001

2000

0.4

800

8.返回data步开始, PDV清空sale_amount中的所有变量值,读取sale_amount的第四条数据

  

Name

  

Salary

Amount

Saly

700

300

进入Do语句,判断while 语句,not(1001 le 300 le2000) 为真,执行Do语句,清空PDV中bonus_criteria的变量值,读取bonus_criteria的第四条观测

  

Low

  

High

Factor

2001

5000

0.6

执行end语句,返回do语句,再次判断while语句

注意:此时会一直陷入Do的循环,因为low和high越来越大,sale_amount的第四条数据的amount=300,not(low le amount le high) 从此一直为真。在读取sale_amount的最后一条观测后,由于sale_amount无数据可读,所以sas会跳转到下一个data步或者proc步等。于是会产生

sale_amount中读取4条记录(第四条记录读取并进入循环但最终都没有被output)

bonus_criteria中读取5条全部记录(后面一直在循环,并且data步终止也是因为数据读完)

bonus观测中含有3条数据。


回复

使用道具 举报

消散2 发表于 2018-8-9 22:42:33 |显示全部楼层

一、文献中的双set,PDV过程

程序如下:

/**sampledataset**/

data bonus_criteria;

input low high factor @@;

cards;

0500 0.1

5011000 0.2

10012000 0.4

20015000 0.6

500110000 0.8

;

run;

data sale_amount;

input name $ salary amount @@;

cards;

Jim500 200

Tom1000 700

Lily2000 1500

Saly700 300

Gery3500 3000

Coliy4500 6000

Jony5000 3000

lary2000 300

Sam1040 200

Jamy5600 1200

Bob3400 500

Salla2600 24

;

run;

/**Use SET/SET join two datasets to derive new variable **/

proc sort data=bonus_criteria;

by low high;

run;

proc sort data=sale_amount;

by amount;

run;

data bonus;

set sale_amount ;

do while(not(low le amount le high));

set bonus_criteria ;

end;

bonus=salary*factor;

run;

1.编译后,PDV含有6个显性变量:low high factor name salary amount. 同时这6个变量初始化值变为缺失

  

Low

  

High

Factor

Name

Salary

Amount

.

.

.

.

.

.

2.接下来系统读取sale_amount中的第一条观测,进入Do循环。

  

Name

  

Salary

Amount

Salla

2000

24

由于amount=24 ,并且此时程序没执行到sale_criteria,又因为low=. high=. 所以low le amount le high为假,所以while语句中为真,执行DO语句

3. 在语句里,第二个set语句产生另一个数据指针,该指针将指向表bonus_criteria的第一条观测

  

Low

  

High

Factor

0

500

0.1

然后执行end语句,并返回Do语句

4. 再次判断while语句,not( 0 le 24 le 500 ) 为假,跳出Do while循环,执行后面的语句bonus=salary * factor; 并output到bonus的第一条观测。

  

Name

  

Salary

Amount

Low

High

Factor

Bonus

Salla

2600

24

0

500

0.1

260

5. 返回data步开头,PDV清空sale_amount中的所有变量值,但不会清空bonus_criteria中的值,因为表bonus_criteria的指针仍然停留在第一条观测上,且程序还未执行到第二个set语句。

6. 读取sale_amount的第二条数据

  

Name

  

Salary

Amount

Jim

500

200

进入Do循环,判断while语句,由于未执行到下一个set语句,bonus_critera的所有变量不被清空,0 le 200 le 500为真, not ( 0 le 200 le 500) 为假,跳到end结束,执行bonus=salary * factor; 并output到bonus的第二条观测

  

Name

  

Salary

Amount

Low

High

Factor

Bonus

Salla

2600

24

0

500

0.1

260

Jim

500

200

0

500

0.1

50

7.跳到data步开始,读取sale_amount第三条观测…以此类推


回复

使用道具 举报

hsubin 在职认证  发表于 2018-8-9 23:28:25 |显示全部楼层
很有意思的一个例子,期待高手来解读
回复

使用道具 举报

l1i2n3i4n5g 在职认证  发表于 2018-8-10 22:15:47 |显示全部楼层
消散2 发表于 2018-8-9 22:39
嗯我搞明白了,供大家参考,欢迎指正,共同进步
结论:双set不利于程序分享,并且如果存在排序问题会导致严 ...
受益匪浅!
回复

使用道具 举报

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

GMT+8, 2018-12-11 22:40