本文主要讲了sas base里编程时数据步的DEBUG嘚利润问题技巧这篇文章首先对BASE中数据步编程可能遇到的BUG分为五大类:
错误可能因为各种原因而产生,无论时简单的句法错误或者是錯误的程序设计。有时即使你的程序是正确的但是由于进入的数据的利润问题技巧,也会产生错误
下面介绍一下DEBUG的五个步骤:
1 首先你偠意识到这里可能会有一个错误存在
2 然后定位到这个错误上
3 通过重新编写代码,或者对各段代码或变量进行分别运行来理解这个错误
4 然后茬程序中修正这个错误
5 最后要弄明白你为什么犯了这个错误怎么才能避免以后再犯类似的错误
句法错误一般比较简单,并且编译器都能指出错误的可能所在例如下面这个例子:
这个错误很简单,编译器能很明白地指出这里有个错误然后提醒我们去修正这个错误。但是甴于编译器并不能从代码中知道我们的意图因此除了指出错误外没提到太多。
下面这个例子SAS就给出了更多的信息:
我们注意看下划线的哋方这里SAS编译器首先读到mistake =这里时,它就明白这可能是一个赋值语句然后需要一个操作符去连接1和200,例如可能是mistake = cats(1, 200) ;或者其它但是具体需偠什么SAS编译器也不能完全知道,因此列出了一堆可能的符号
但是有时候程序里有一些语法错误,但是运行时却没有报错例如:
这里运荇后并没有报错,但是因为程序很短我们看一下就知道第3行和第6行有错误,第三行是少了一个双引号第六行是多了一下双引号,还有僦是x y z并没有输出到日志中
如果上面这个错误的程序再复杂一点,例如:
married"这样age和status这两个变量就没处理了。我测试时没有出现更多的日志信息但是由于这种错误的出现,很可能日志的信息非常混乱并且会误导人,让人很难明白到底是哪里出错了因此,当出现一些不好解释的结果时对于日志的错误提示,我们也要先搞清楚它提示的对不对
修正一个利润问题技巧是非常困难的,因为编译器并都不知道芓符的意思因此,用一个对不同类型的字符或标记使用不同颜色的编译器非常有用另外,良好的代码书写习惯也有非常有用例如DO循環后,要加入一个END才行有时候我们经常会忘记加这个END,不过在SAS中如果DO后面没跟相应的END是通不过编译器的。
当出现一大堆错误时我们朂好先解决第一个利润问题技巧,或者后面的利润问题技巧如果非常好解决的话也可以先解决但是不要想着努力地解决所有的利润问题技巧,因为有可能当我们把第一个利润问题技巧解决后所有的利润问题技巧都消失了。
句法错误一般在编译时就被发现了但是有些错誤并不是句法错误,但是一样在编译时被发现例如:
这里没有下划线,因此没有明显的句法错误然后呢,日志里给出了很多的提示泹这些提示很让人迷惑。其实如果认真看一下就知道只是第一行少了一个分号。由于编译器是通过关键词来识别程序的因此如果你少叻一个分号,就会使编译器无法正确地读到关键词因此编译器会发现错误,但发现的却不是真正的错误所以一般出现一大堆错误的时候,很可能只是一些非常小的原因造成的
考查一下下面两段程序错误的异同:
LOG1的提示是在编译后给出的,而LOG2的提示是编译时给出的都昰由于没有相应的逻辑库,为什么会出现这种差异呢原因是第二种情况下,编译器一定要先从PROGRAM DATA VECTOR (PDV)读取变量名因此就会在编译的时候发现沒有逻辑库名。
另一种情况是未初始化的提示:
Y没有被赋值但为什么在编译后才给出提示呢,原因上因为第一次出现Y时RETAIN语句在编译时賦给Y一个值。并且有时候通过编译器没有发现的方式进行赋值也会报未初始化的错。
有时候字符和数字进行转换时也会出错例如:
这裏为什么Y是空值呢,因为substr时的N是数字然后其格式为best12,这里用PUT转换成字符类型后它有12个字符大小,而N=763只有三个字符因此左边的九个字苻为空,因此最终的Y也为空
执行时错误一般是可以通过编译,但却不能正确执行的错误发生这类错误的原因有三:除0,包含缺失值的算术表达式函数或数组溢出。
这里没有error并且还能执行,并且提供的提示也可以很快地定位到错误
如果你想知道变量的值时,可以用put _all_ ;語句PUT很好用,可以一步一步地测试你的程序数据是否正确
这里有两个错误,第一个比较简单就是SAS无法识别??因此将其作为错夨值。另一个错误SAS没有给出说明只是提示说有错误。其实我们将程序运行一下就知道这里的Y值读取错误,得到的两条数据是x=. y=1和x=2 y=3这和峩们预期是有差别的。我们可以用infile cards truncover ;语句解决这个利润问题技巧
考查运行时错误的严重性时我们可以看一下下面的例子:
这里因为并没有對数据集w进行变量group的排序,所以出现错误我们可以在group变量后加入NOTSORTED选项,这样程序将不再检查W是否用GROUP排序过了
另外一个错误是数组溢出,例如:
这里数组a[4]明显溢出
我们可以用许多系统选项来控制错误的严重性或看看我们是否可以得到一些信息。
用这段程序就可以得到系統选项及其作用这里我就不列出结果了。
在这里要强调一下由于缺少结果的分号,很容易删除一些永久的数据集这一点非常致命的,例如:
这里SET 和 PROJECT.MAIN都将被当作数据集进行处理,因此程序执行时数据集PROJECT.MAIN就很容易被修改了。这里我们可以用NOREPLACE这个选项这样,输出到非work嘚数据集都必须是新建的另一个方法是在LIBNAME语句中加入选项: ACCESS=READONLY。
一个经典的逻辑错误就是“缺一个”:你要处理38个数据集你现在要处理嘚是第23个,问你还有多少个数据集没处理完如果答案是38-23,错误就出现了正确答案是38-23+1。当你把第23个数据集处理完后38-23就是正确答案了。
┅些有关楼梯的利润问题技巧我们总是花很多精力处理第一步和最后一步,原因就是第一步没有前一步而最后一步是没有再上一步,茬处理利润问题技巧时我们也经常在第一步或最后一步出错。
下面的例子将详细地解释这类错误:
我们以ID为群标识然后将数据分别读箌每一个群中。实现思路如下:我们先设置一个临时变量test然后将这个变量与下一个ID值进行比较,如果相同则说明是同一个群,如果不哃则说明是一个新的群,这里就可以输出数据实现程序如下:
这里日志并没有报错,并且也生成了两条数据但是我们仔细地看这两條数据时,就会发现有错误存在:
我们看到在第一步时,我们没有得到任何输出值因为第一步时没有ID的值,为什么呢原因是没有第┅步的上一步,因此变量test没有初始值因此,我们加上下面一条语句可以修正这个错误:
这里我们再运行日志中会出现报错。这是因为茬第二步也即本程序的最后一步时,因为没有下一步因此结果并没有输出出来。这里我们需要在infile语句后面加上END=EOF然后在最后加上:if eof then output ;
最後,我们将得到如下结果:
结果似乎完全正确了是否我们就做完了呢。不是的如果我们再加一个ID值,也即产生一个新的群这个群只囿一个值0,这时的结果如下:
为什么第三个群里会出现三个值而不是一个值这是因为retain让数组V的值保持原值,而不是清空掉因此V2,V3都保留了第二个群的值因此,我们在输出前要先清空原来的值另外,这里我们假设每个群的值的个数不大于5这也可能引起利润问题技巧。这种利润问题技巧我们一定要预先考虑到而不是等系统报错了我们才来解决。
另一个容易犯的逻辑错误是"find the best"寻找最优值。我们看一下丅面的程序:
这个程序的意图是找到每个州销售量最高的三个店这段代码看似没有利润问题技巧,但如果我们有四个店其销售量相等且朂高这时会出现什么情况呢?这时cnt可能增加多次我们可以用下面的语句来严格限制cnt的增加:
但是上面的语句一样可能会出现利润问题技巧,即LAG函数是条件运行的在第一条数据时他是不会执行的。
在实战中遇到的BUG可能更复杂,但是掌握好这些基本技能加上经验,可鉯更好地解决这些利润问题技巧
下面首先介绍一个简单的数据利润问题技巧的例子:
这里我们很容易发现一个错误就是if else语句里面没有包括大于20的数值的选项,这样得到的x_edit可能不完整还有一个可能的错误是:x的值可能是为非负数,而第一个if时并没有处理
下面来讲一讲复雜一点的数据错误:
上面代码中,第二个sort(第7行)中的nodupkey选项就表示其输出结果w2是没有重复值的但是我们来看一看17行的程序的打印结果:
為什么会出现X在第2行和第3行是一样的结果,都是ab呢难道原来的代码有错误吗?我们看到第15行后的log中记录到一个warning实际上我们的代码是没囿错误的,我们可以通过下面的语句来查看数据集w2中满足条件x=’ab’的记录数:
这里只有一条数据满足条件。这样结果没错代码也没错,那可能是数据有错误我们先看一个w2数据集的所有数据
;merge会将第一个数据集的格式作为结果数据集的格式,因此在w1时,x的格式为2个字符而w2中x的格式为3个字符。所以程序将w2中的第三条记录中的x的值强制转换成了2个字符的ab也就出现了我们的错误。
这篇文章主要讲了错误可能发生的类型这对SAS编程的初学者来说是非常重要的。但是这仅仅是一个开始,当开始编写复杂的程序时你将会意识到有一些错误可能是由于编程过程自身所引起的,因此你必须持续地学习如何避免错误,如果不幸遇到错误就要定位错误,修正错误
模块化开块也許是最简单也最重要的防止错误发生的工具,SAS作为一个面向步骤的编程语言对防止错误也非常有用。因为每一步我们都有一个特定的输叺和输出这使得当发生错误时,我们能方便地定位到错误的位置并且每一步出错的概率远远小于整个程序都出错的概率,因为整个程序可能需要很多复杂的统计或其它自定义的代码来报出错误或警告
模块化程序开发可以使得你的代码能很好地重用,一旦你这样做你會发现你基本不用花多少时间去检查,因为这些代码已经用在了很多地方并且代码也经过多次检验。
另外对数据的深入了解,对SAS如何笁作的了解以及对项目利润问题技巧的了解对我们测试SAS代码都有着重要的作用
最后说一下:简单就是美。我们编写的代码除了能完成我們的工作并且尽量少的bug外,最好是能让人很直观地看懂至于debug时的态度利润问题技巧,可参考前一篇文章:SAS Debug初手者手册
加载中请稍候......