Data步双output、双set的妙用

前两天在一个SAS QQ群上碰到一个处理数据实际问题,觉得挺有意思的,分享给大家。

问题:“sxlion:   你好!

我的问题是要把ML.ped文件里面的全部按照文件ML.bim改为1和2. 修改的标准为:
 ML.ped的列数为ML.bim的2倍.
如果ML.ped的2n-1或2n列等于ML.bim表的第n列的第一个字母,那么ML.ped的2n-1或2n列就为1,否则为2.
 modi.txt是我修改的部分数据,通过这样的程序来实现:
 data ML1;
  set ML;
array geno{86} _all_;
  if geno{1}=”A” then var7=1 ; else  var7=2;
if geno{2}=”A” then var8=1 ; else  var8=2;
  if geno{3}=”T” then var9=1 ; else  var9=2;
if geno{4}=”T” then var10=1 ; else  var10=2;
.
.
.
run;
冬末”
三个数据附件:ML.ped   ML.bim modi.txt (点击数据下载地址 均可用记事本打开)。
思路:看了冬末给的代码,能了解个大概的意思,可能需要宏把“if … then … else …”用宏代替,不过还得看懂数据,了解实际需求。我把数据ml.ped打开一看,发现里面是字段是A,G,T,C,哈哈,这不是DNA的碱基么,嘌呤,嘧啶什么的,挺有意思的,估计是与基因排列规律的有关数据,然后继续查看ml.bim,里面也是些AGTC字母,应该是参考碱基序列。最后看看目标数据modi.txt,只有部分修改好的。拿到数据的第一反应是,数据查询,用select into 建立宏变量列表解决这个问题,后来发现有个列数倍数的问题,实现起来需要嵌套宏,难度加大比较麻烦,放弃;还想到hash大杀器。。。
对于SAS来说,如果一个简单的问题(因为数据量太小了),动用太高级的武器是不值得的。后来想想双set不是能很好的解决这个问题么? 只是在构造循环的时候需要考虑2倍的问题。 如果问题能进一步简化,不是更好吗 ?  把一个观察值重复两遍的比较,如果构建一个重复不就可以了,于是双output就用上了。于是敲了几行代码,解决了。
解决代码:

data mlped;
input var1 :$5. var2 :$5. (var3-var92) (~$1.) ;
cards;

H1000 H1000 0 0 1 2 A G T C T C G A T C C T T A C T T C T C G A A G T C C T C G A C T C C A A … G
H1003 H1003 0 0 1 2 A G T T T C G G 0 0 0 0 0 0 0 0 C C T T 0 0 G G 0 0 C C G G A A T T C C T…  C
…/*将ML.ped数据复制过来*/

H1004 H1004 0 0 1 2 A G T C T C G A T C C T T A C T T C T C G A A G T C C T C G A C T C C A  C … C G

;
run;

data mlbim;
input a $4.@@; output; output;  /*双output构建新的查询数据*/
if _N_ = 43 then stop;
cards;
A T T G T C T C T T G A T C C A T C A A A G G G G T C C T A G C C C G C C G A T G T C
G C C A C T A T C C A G C T G C C A T G G A A A A C T T C G A T G G A T T A G C A G G
;
run;

data modi;
set mlped;
array geno[86] var7-var92;
array newgeno[86] nvar7-nvar92;
do i= 1 to 86 ;
set mlbim point=i;    /*双set ,使用point定位查询数据集ml.bim */
if geno[i]=a then newgeno[i]=1 ;else newgeno[i]=2;
end;
output;
run;

proc print data=modi;
var nvar7-nvar92;
run;

运行结果:

NOTE: 从数据集 WORK.MLPED. 读取了 2020 个观测
NOTE: 数据集 WORK.MODI 有 2020 个观测和 179 个变量。
NOTE: “DATA 语句”所用时间(总处理时间):
实际时间 0.04 秒
CPU 时间 0.03 秒

运行结果非常快,结果与给的参考结果modi.txt一致,Bingo!

二级分组百分比构成图

引子: 有朋友在QQ群上问道的一个问题,这种图有个名称叫份额图(share charts),比较有代表性。注意这个是等宽的,还有种不等宽的叫mekko图。

已有临床试验数据集bylw.dose6631,一共19893条观察值, 变量有 pid、   time、  group1 、dosegroup, 分别表示病人的id号、时间点(4,8,12)、组类型(对照和干预组)和剂量类型(1,2,3)。

这时很想知道知道使用样本的构成情况,很显然用下面代码很好搞定:

libname bylw "D:\SAStem";

proc  gchart data=bylw.dose6631;
vbar group1/
discrete  type=pct group=time subgroup=dosegroup  inside=subpct g100 width=12;
run;
quit;

得到的图如下:
原始图表
这个胚图真够丑的,这个暂且不论。
我们的目标图要类似这样的

目标图表

当然这个还是有点丑。丑归丑,你会发现你翻烂了SAS help文档,试过了所有的proc gchart的option,最终发现还是做不了。

小结:

这个时候,说明直接画这种统计图是行不通的,尽管gchart本身除了画图,内置了一些统计功能,但是他得到的数据图形也遵循统计学的原则。例如time=4是的干预组的总样本数是大于对照组的,所以干预组的柱形图高于对照组的。这个是完全合情合理的。

转换思路:
但是现在我们需要把所有的柱形图高度调到一致,并且纵坐标为0-100的百分比刻度。这个时候,我们需要采取间接的方法。那就是1,用专门的统计过程得到分析结果数据;2,用结果数据来画图。对于本文,使用如下代码:

proc freq data=bylw.dose6631;
table time*group1*dosegroup/
nocum nopercent OUTPCT out=bylw.count ;
run;

 得到数据集bylw.count:

Obs    time    group1    dosegroup    COUNT    PERCENT    PCT_TABL    PCT_ROW    PCT_COL
                    频数统计  总频数百分比 双向表频数百分比 行频数百分比 列频数百分比
  1      4      对照         1          313     1.5734      4.7203    11.0445    44.1467
  2      4      对照         2         1229     6.1781     18.5342    43.3663    44.5451
  3      4      对照         3         1292     6.4947     19.4842    45.5893    40.8473
  4      4      干预         1          396     1.9906      5.9719    10.4293    55.8533
  5      4      干预         2         1530     7.6911     23.0734    40.2950    55.4549
  6      4      干预         3         1871     9.4053     28.2160    49.2757    59.1527
  7      8      对照         1          346     1.7393      5.2179    12.2089    48.8701
  8      8      对照         2         1155     5.8061     17.4182    40.7551    44.4744
  9      8      对照         3         1333     6.7008     20.1025    47.0360    40.0782
 10      8      干预         1          362     1.8197      5.4592     9.5338    51.1299
 11      8      干预         2         1442     7.2488     21.7463    37.9774    55.5256
 12      8      干预         3         1993    10.0186     30.0558    52.4888    59.9218
 13     12      对照         1          316     1.5885      4.7655    11.1503    47.7341
 14     12      对照         2         1160     5.8312     17.4936    40.9315    47.9141
 15     12      对照         3         1358     6.8265     20.4796    47.9181    38.2751
 16     12      干预         1          346     1.7393      5.2179     9.1125    52.2659
 17     12      干预         2         1261     6.3389     19.0167    33.2104    52.0859
 18     12      干预         3         2190    11.0089     33.0267    57.6771    61.7249

 

SAS的统计数据就是全面啊, 为了让每一个二级组的和为100%,那就选PCT_ROW这组数据。下面根据这组数据画图:

/* Angle the label for the response axis */
axis2 label=(angle=90 '历年传播途径构成比(%)' )
 minor=none ;
proc  gchart data=bylw.count;
vbar group1/discrete subgroup=dosegroup group=time g100
         sumvar=pct_row
         inside=sum
         width=12   raxis=axis2 ;
run;
quit;

得到预期图表

毛胚图

显然这个图基本上达到了预期的要求。但是太难看了,主要:1,各部分的比例;2,颜色搭配。下面进入漫长的调图期,要画得一张美图,需要花时间的,就像“这个世界上只有懒女人,没有丑女人”一样的道理。

微调了一下,有所改观,还可以继续调整。

成品图

代码:

/* Set the graphics environment */
goptions reset=all hsize=8 vsize=4.5 cback=white htext=13pt;

/* pattern 设置各组的颜色; */
pattern1 v=solid color=cx3F41D5; /* reddish color */
pattern2 v=solid color=cx589DEF; /* this is the hex rgb color for mild blue */
pattern3 v=solid color=cxA0C5F1; /* kind of a seafoam green */
/* 横坐标 */ /*axis1 label=none value=none; */
/* 纵坐标 */
axis2 label=(angle=90 ‘药物临床试验样本构成比(%)’ ) minor=none ;

proc gchart data=bylw.count;
vbar group1/discrete subgroup=dosegroup group=time g100
sumvar=pct_row inside=sum noframe
width=10 SPACE=6 raxis=axis2

/* gaxis=axis1 */
;
run;
quit;

线性规划之合金原料配比问题

前言:虽然这是个比较简单的线性规划问题,但是怎么把问题转化为SAS代码,中间需要一定的小技巧,特叙此例。

问题:

Metalco公司希望得到一种新的合金,其中锡40%、锌35%、铅25%。原料合金的成分如下表:

合金

原料代号

成    分

价格

锡含量 / %

锌含量 / %

铅含量 / %

美元/磅

1

60

10

30

77

2

25

15

60

70

3

45

45

10

88

4

20

50

30

84

5

50

40

10

94

工厂怎样从这几种合金原料选择来制得需要的合金,要求生产成本最小。
分析:
显然,这是个线性规划问题。
首先分析下目标,目标是生产成本最小,也就是生产单位重量(磅)的新合金用到的原料合金总价格最低。 Continue reading 线性规划之合金原料配比问题

学习SAS的小故事2——手摇式计算机

大学时代,最喜欢两个老师,他们都是已经退休后被返聘的老教授。其中一个就是教多元统计的余老师,他教我们多元统计,还教SAS编程。在他的一次统计课上,提到过当年农科院需要统计农作物数据的时候,用到了手摇式计算机,据说算一个路径分析,算几天才算出一个结果。手摇式计算机,也许80后可能没看过,90后可能没听说过,00后。。。 Continue reading 学习SAS的小故事2——手摇式计算机