SAS笔记(1) PDV与数据读入

一点吐槽:其实我是不喜欢SAS的。当然,我不喜欢她,并不代表她不好,实际上在某些应用场景下SAS是款很优秀的软件。我的数据分析之路始于R,品尝过R的灵活与简洁(不论是软件安装还是语法)后,再来学习SAS,的确提不起兴致。然而由于:1.导师的项目数据量较大(几Gb到几十Gb);2.之前的项目代码师兄已经用SAS很优美地实现了;3.我莫名地当上了该项目负责人,要带着师弟师妹做该项目。我也只好硬着头皮学习SAS。奈何现在脑力大不如前,看的东西越来越记不住,于是下定决心梳理一下SAS相关知识。

1. DATA步简介

在SAS中,我们使用DATA步来读入数据,DATA步在读入数据时实际上有两个阶段:编译(compilation)和执行(execution)。过程如下:

  1. 在编译阶段中,逐个扫描语句,如果发现语法错误,SAS报错并终止运行;如果编译阶段中没有发现任何语法错误,进入执行阶段。
  2. 在执行过程中,DATA部读入第一条数据,在SAS中创建第一条观测;读入第二条数据,在SAS中创建第二条观测;读入第三条数据,在SAS中创建第三条观测……直至读入最后一条数据并在SAS中创建最后一条观测。我们可以把这个过程当做隐式循环(和DO,DO WHILE,DO UNTIL语句区分,它们是显示循环)。

需要注意的是,并不是DATA步中的所有语句都是在执行阶段运行,事实上,可以把DATA步语句分为两类:可执行语句(executable)和声明语句(declarative)。
声明语句只在编译阶段起作用,它可以放在DATA步的任何位置。下面是一些基本的DATA步声明语句:
LENGTH:设置内部变量长度
FORMAT:设置变量输出格式
LABEL:设置变量标签
DROP:指示输出文件中删掉哪些变量
KEEP:指示输出文件中包含哪些变量

与声明语句不同,可执行语句在DATA步中顺序很重要。比如从外部读取一个文本文件,我们必须以INFILE语句开始,告诉SAS从哪里读文件;然后输入INPUT语句,告诉SAS怎么读该文件。所以,INFILE语句必须在INPUT语句前面,顺序很重要。

2. DATA步的编译阶段(DATA Step Compilation Phase)

SAS从外部读入原始数据(raw data)时,会在编译阶段开始时创建一个输入缓冲区(input buffer)来存储raw data。如果是从外部直接读入SAS数据(.sas7bdat文件)则不会创建输入缓冲区。SAS在编译阶段还会创建PDV(program data vector),PDV其实就是内存中的一块区域,通过PDV将读入的raw data的每一条数据变成SAS数据集中的每一条观测。在PDV中有两个自动变量,__N__和__ERROR__。__N__=1表示正在创建第一条观测,__N__=2表示正在创建第二条观测,依次类推。__ERROR__只有0和1两个取值,等于0表示在创建当前观测时未发现错误,等于1表示在创建当前观测时发现错误。除了这两个自动变量外,PDV中还有DATA步在创建的数据变量。

假设在我们电脑D盘里有一个student.txt文件,内容如下(第一行红字表示每个字符的所占列位置编号,不是文档内容)

12345678901234567890
Barbara 61 12D
John    62 175

现在我们用DATA步读入这个文件,并计算每个学生的BMI,看看PDV的工作原理。代码很简单:

data ex1;
infile ‘C:\student.txt‘;
input name $ 1-7 height 9-10 weight 12-14;
BMI = 700*weight/(height*height);
output;
run;
  1. 一开始,PDV中只有__N__,__ERROR__这两个自动变量。
  2. 代码运行到 input name $ 1-7 height 9-10 weight 12-14;时,PDV中会按照input后变量的顺序创建NAME,HEIGHT,WEIGHT三个变量,D表示dropped,K表示kept。只有带K的变量才会output到数据集中。
  3. 代码运行到BMI = 700*weight/(height*height);时,PDV中创建BMI这个变量

在编译阶段,SAS会检查语法是否正确,在编译结束的时候,会创建SAS数据集的内容描述,包括数据集的名字,观测数,变量名,变量数目,变量类型,所有这些内容都可以通过CONTENTS输出。

3. DATA步的执行阶段(DATA Step Execution Phase)

  1. 在执行阶段的开始,自动变量__N__会被初始化1,自动变量__ERROR__被初始化0。一旦INFILE语句识别了我们待读取文件的路径,INPUT语句就会把待读取文件的第一条数据复制到输入缓冲区。
  2. 接着,我们的输入指针(input pointer,下图的红色箭头)会在(@)输入缓冲区的开始处。
  3. 然后,输入指针(红色箭头)会根据input语句定义的方式读入输入缓冲区的这条记录,并移动输入指针,在我们的例子中是将1-7列读入NAME,9-10列读入HEIGHT,12-14列读入WEIGHT,此时输入指针位于第15列(这也有助于理解@@的作用)。将记录写入到PDV,因为WEIGHT变量类型错误,所以WEIGHT变量值为空(.),同时__ERROR__会变为1,因为WEIGHT为空,所以BMI也为空。
  4. 然后执行OUTPUT语句,将PDV中的这条数据输出到我们的SAS数据集--WORK逻辑库中的ex1。到此student.txt中的第一条数据已读入SAS数据集。
  5. SAS返回到DATA步的第一条语句,也就是data ex1;开始读取student.txt中的第二条数据,此时__N__变为2,__ERROR__重新置为0,其余过程同上。如此往复,直至我们的输入指针遇到EOF(End Of the File),退出循环。DATA步结束。

在我们的这个例子中,如果我们不使用OUTPUT也可以读入该数据,这是因为在DATA步中,当用户没有显式指定OUTPUT时,SAS会隐式调用OUTPUT。不论显式还是隐式output,它们的作用都是讲PDV的那条数据output到我们的SAS数据集中。

参考资料:《Handbook of SAS? DATA Step Programming》

时间: 2025-01-12 09:20:20

SAS笔记(1) PDV与数据读入的相关文章

OpenSceneGraph 笔记--如何导出三角形数据

OpenSceneGraph 笔记--如何导出三角形数据 转载:http://blog.csdn.net/pizi0475/article/details/5384389 在OpenSceneGraph开发中,为了方便会经常使用到一些不是三角形片的数据,比如四边形等数据.例如画一个管子用四边形带比用三角形片好计算得多.比如现在我们要画一个由两个平面组成的面,我可以这样做: osg::Geode* geode=new osg::Geode;    osg::Geometry* polyGeom =

Python学习笔记_Chapter 6定制数据对象

1. 有用的BIF a. 判断字符串中是否包含子字符串 1 if s_a in s_b: b. pop() 描述:从指定的列表位置删除并返回一个数据项. 1 (sarah_name,sarah_dob)=l_rah.pop(0),l_rah.pop(0) 2 #pop(0)中0位置为list中第一个数据项 3 #第一次执行pop赋值给sarah_name c. strip() 输入的是字符串,返回的是列表 d.open 读文件时可以多种方式打开文件,取出的数据是不同的,可以是文本也可以是二进制.

《Spring实战》读书笔记--SpringMVC处理Multipart数据

<Spring实战>读书笔记--SpringMVC处理Multipart数据 1.Multipart介绍 1.1 Multipart形式的数据 Multipart格式数据会将一个表单拆分为多个部分(part),每个部分对应一个输入域.在一般的表单输入域中,它对应的部分会放置文本型数据,如果是文件上传形式,它对应的部分可以是二进制. 1.2 Multipart/form-data请求方式 Multipart/form-data是建立在HTTP的POST请求方式以上的请求,其一般用于HTTP文件上

Sharepoint2013搜索学习笔记之设置业务数据内容源(六)

Sharepoint搜索爬网组件支持爬Business Data Connectivity Service 承载的外部数据,关于Business Data Connectivity Service设置外部数据源,详请请参考:如何:在 SharePoint 2013 中为 SQL Server 创建外部内容类型,爬网设置步骤如下: 第一步,进入管理中心,点击管理应用程序,点击search service 应用程序进入到搜索管理配置页面,点击内容源 第二步,点击新建内容源,给内容源命名,在爬网内容类

集算器协助java处理结构化文本之数据读入

JAVA只提供了指定分割符等最基本的数据读入功能,而其他常见功能都需要自己从底层去实现,比如:按列名读入指定列.指定列的次序.指定数据类型.无分割符等等.JAVA实现这类功能虽然不难,但代码很繁琐,很容易出错. 使用集算器来辅助Java编程,这些问题都不需要自己写代码解决.下面我们通过例子来看一下具体作法. 文本文件data.txt是tab分割的文本文件,有30个列,第一行是具有业务意义的列名,现在需要按列名读入这几列:ID.x1Shift.x2Shift.radio,并按业务公式“((x1Sh

将Excel中的数据读入到GridView控件中

使用Excel文件作为数据源,其实现的代码为: Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath("excel.xls") + "; Extended Properties=Excel 8.0; 实例代码: private DataSet CreateDataSource()    {        string strCon;        strCon = "Provider

Python学习笔记_Chapter 5处理数据

1. 方法串链(method chaining).函数串链 1 import os 2 os.chdir('C:\\Users\\hwx222865\\Documents\\Pyton_lib') 3 with open('james.txt') as data: 4 s_line=data.readline() 5 james=s_line.strip().split(',') #方法串链 6 print(sorted(james_s))#函数串链 BulletPoint: 1. split(

python后端将svc文件数据读入数据库具体实现

如何用python将svc文件的数据读入到MySQL数据库里,在此直接上代码了,感兴趣的朋友可以贴代码测试: import pandas as pd import os from sqlalchemy import create_engine # 初始化数据库连接,使用pymysql模块 # MySQL的用户:root, 密码:123456, 端口:3306,数据库中已存在的数据库名:python1 engine = create_engine(r'mysql+pymysql://root:[e

SAS笔记(2) RETAIN语句

本文重点: 使用RETIAN,INPUT在每次循环执行时保留上一次PDV中的变量值. SUM语句和SET语句会自动RETAIN变量. 1. RETAIN语句 1.1 Example 1 先来看看在DATA步不使用和使用RETAIN语句的差异 没有使用RETAIN: DATA WITHOUT_1; PUT "Before the INPUT statement: " _ALL_; INPUT X @@; PUT "After the INPUT statement: "