全部版块 我的主页
论坛 数据科学与人工智能 数据分析与数据科学 SAS专版
1940 5
2011-11-30
我想做一个测试,看看以下这个简单的题目到底能有多少种不同的编程方法:

题目:给定一个SAS数据集a,它只含有一个字符变量col1,比如:

复制代码

要求产生一个数据集b,它也只含有一个名为col1的字符变量,要求a中的字符串在b中出现,且出现次数为其自身的字符串长度,即:

                                           Obs    col1
                                             1     abc
                                             2     abc
                                             3     abc
                                             4     1234
                                             5     1234
                                             6     1234
                                             7     1234
                                             8     ef
                                             9     ef

问产生数据集b的代码如何写?

----------------------------------------------------------------------------------------------------------------------------------------------------

以下抛砖引玉,我给出3种不同的方法:

**************************************

方法(1)——用output来解决问题:

复制代码

用一次output,系统就将当前的col1变量值写到b中一次,重复length(col1)次,结束当前的col1变量值,换a集的下一个变量值再重复此过程,直到a中col1的所有内容取尽为止。

这是最简单的方法。

**************************************

方法(2)——用保留数组来做:

我们的目的是产生一个保留数组,比如名为colcol的数组,其内容为:

colcol1   colcol2   colcol3   colcol4   colcol5   colcol6   colcol7   colcol8   colcol9
abc        abc        abc        1234     1234      1234     1234      ef           ef

之后再将这个数组(数组都是横着的)转置成竖着的方向,冠名为col1。

第一步,我们要知道需要创建的colcol数组究竟应该有多少个元素,比如上例中为9,这个9就是a的变量col1中字符串长度的总和,所以,我们应该先统计a的变量col1中字符串长度的总和,并将其储存起来,以便其他程序调用。程序如下:

复制代码
rowsum就是一个长度累加器,在取尽a中col1变量值后,我们将这个累加值赋给number宏变量,这样其他程序即可调用该值。

第二步,产生colcol 保留数组,并填入我们想要的内容:

复制代码

其中index_col 为保留变量,它的功能是数组的指针,在每次data b大循环开始时,它总指向数组中需要开始填写的地方。

这个程序结束后,我们能得到如下的b集:

   Obs   colcol1   colcol2   colcol3   colcol4   colcol5   colcol6   colcol7   colcol8   colcol9
    1      abc        abc        abc       1234      1234      1234      1234       ef         ef

第三步,转置b集,并将竖着的字符串们统一冠名为col1,具体程序为:

复制代码

之后,我们就得到了如题目所要求的结果。

**************************************

方法(3)——这是我想了很长时间才想出来的疯狂方法,这个方法很怪,是我的“杀手锏”,它是以transpose为核心的方法:

第一步,查清楚a中col1 对应的所有字符串中最长的那个字符串的长度,并将其储存起来:

复制代码

我们将这个长度最大值赋给宏变量len_max,以便其他程序调用。

len_max的值按题目给出的a集来看应该是4。

第二步,产生如下的b集:

                      Obs    col1    colcol1    colcol2    colcol3    colcol4
                       1       abc        1            1            1             .
                       2       1234     2            2            2            2
                       3       ef          3            3             .             .

其中,colcol 变量行若有值,其值为对应行数,且colcol 系列变量中每一行究竟有多少个变量有数值,这取决于每一行col1字符串的长度。

产生如上结果的程序为:

复制代码

现在你也许看不懂为什么要这样做,但看完第三步你就应该清楚了,这都是为了运用transpose产生理想的结果!

第三步,运用transpose产生与题目中所要求的答案相近似的结果:

复制代码

针对第二步的结果,运用上述transpose会产生如下效果:

                                 Obs    col1    _1234    abc    ef
                                   1    1234      2          .        .
                                   2    1234      2          .        .
                                   3    1234      2          .        .
                                   4    1234      2          .        .
                                   5    abc         .         1         .
                                   6    abc         .         1         .
                                   7    abc         .         1         .
                                   8    abc         .         .          .
                                   9    ef            .         .         3
                                  10    ef           .         .         3
                                  11    ef           .         .         .
                                  12    ef           .         .         .

注意产生的新b集中变量的名称及内容!这就是在transpose中同时运用id及by的结果!

我们已经很接近题目的要求了!

上述结果唯一的不足在于transpose操作破坏了原有col1中字符串的排序,不过没有关系,第二步中的colcol=_n_;语句就是为此设置的,它使得上述结果中最后3列的数字成功显示其对应字符串原来的顺序!这样做是以便日后排序之用!

第四步,查明新b集中除col1之外所有的变量名,并将其作为字符列表(就是字符串)储存起来,以便调用:

复制代码

被赋值的variable宏变量的内容应该为:_1234 abc ef

第五步,将第三步产生的新b集的后3列相加,算出行和sumnum,若sumnum不为空则行记录保留,若其为空,则删除该行记录,另外,删除多余变量:

复制代码

结果为:

                                      Obs    col1     sumnum
                                        1     1234       2
                                        2     1234       2
                                        3     1234       2
                                        4     1234       2
                                        5     abc         1
                                        6     abc         1
                                        7     abc         1
                                        8     ef           3
                                        9     ef           3

第六步,对上述b集按sumnum排序,恢复col1本来的顺序,并删除sumnum变量:

复制代码

这样我们就得到了题目所要求的结果!


**************************************

总结:

以下三段代码是等价的,它们都可以解决问题:

(1)

复制代码

(2)

复制代码

(3)

复制代码

**************************************

除以上三种外,应该还有很多其他方法,希望众位牛人可以发表自己的方法,越奇怪越好!

期待中...
二维码

扫码加我 拉你入群

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

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

全部回复
2011-12-1 15:11:47
proc iml,
根据字符串长度repeat矩阵。
二维码

扫码加我 拉你入群

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

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

2011-12-1 15:25:44
顶一个
二维码

扫码加我 拉你入群

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

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

2011-12-4 06:21:39
The first one is the right one. Others are clumsy.
二维码

扫码加我 拉你入群

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

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

2011-12-4 14:09:19
bobguy 发表于 2011-12-4 06:21
The first one is the right one. Others are clumsy.
我发这个帖的初衷是想训练一下我自己的SAS语言运用能力。

所以,可能目标就不是“找出能解决问题的最佳代码”,而是“找出能解决问题的所有可能代码”。

调动所有可能的技术及方法完成同一道题,可以有效的提升SAS编程技能。

比如方法(3),我绞尽脑汁终于发现,其实用transpose也可以解决问题。

虽然它可能不是最佳的,但它给了我一次熟悉transpose中id及by用法的机会。

要想找出b集中所有变量的名字,这不得不使我上网搜索sql 的具体用法。

用最少的题目覆盖尽可能多的SAS方法,是最经济的练习方法。

比如楼上说还可以用iml ,这很好,确实可以,我就没有想到。

方法上,不求最好,但求最怪、最多。

这可能更加偏重考察一个人的创造力。
二维码

扫码加我 拉你入群

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

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

2011-12-5 00:58:51
meishanjia1900 发表于 2011-12-4 14:09
我发这个帖的初衷是想训练一下我自己的SAS语言运用能力。

所以,可能目标就不是“找出能解决问题的最佳 ...
I understand your motivation.

二维码

扫码加我 拉你入群

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

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

相关推荐
栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群