Lesson 1 数据集的建立
Lesson 1 数据集的建立
简介
程序的基本组成
1 数据步
data 数据集名; /*新建数据集,导入储存数据*/
2 过程步
proc 操作 <options>; /*处理数据*/
run;/*结束语*/
1 数据集的基本输入方式(数据步)
1 在SAS直接输入
data ma.fsh; /*数据集起名为ma.fsh,ma是逻辑库名,fsh是ma中的某一数据集名*/
input age weight height; /*数据集中输入3个变量,命名为age、weight、height*/
cards; /*标志着后面就是数据输入;或者用 dataline */
26 62 171
28 58 166
;
注意事项
任何语句的结束需要加一个分号“;”,必须是英文状态下的分号。
数据输入后,分号要另起一行,不能紧接在数据后输入。
输入的字母不区分大小写
输入格式不要求必须左对齐或右对齐
初学者尽量不要把多个语句放在一行。如:
Input id age; cards; 1 23; 初学者最好不要用这种输入方式
SAS数据集名或变量名太长时,可加下划线,如:
Data drinking_in_beijing; Input test_score;
2 引用外部数据
文件--导入数据
2 数据变量类型
SAS中的变量只有两种类型:字符型(character)和数值型(numeric)。
日期是被看作是数值型,所有日期型变量被作为是输入日期与1960年1月1日之差。如1980-1-1, SAS会认为这个值是7305。
不同类型的变量在input语句输入时需要指定相应的格式
1 字符型character
data fh;
input gender$;
/*$表示gender变量是个字符型,字符型变量一定要在变量后面加一个$符号,变量和$之间加不加空格均可。*/
cards;
female
male
;
2 数值型numeric
包括数值与日期
- 数值
如果你想让SAS有选择地读取你的数值,可以在变量后加上w.d的格式。其中,w表示数值的位数(包括小数点),如2.3的位数是3;d表示数值的小数点位数。
data fh;
input x 4.2; /*变量后的4.2表示变量x的宽度共4位,其中小数点2位*/
cards;
12
2.1
15.6
23.46
;
proc print;
run;
- 日期
SAS日期格式 | 举例 | SAS日期格式 | 举例 |
---|---|---|---|
DDMMYY6. | 280713 | DDMMYY8. | 28/07/13 |
MMDDYY6. | 072813 | MMDDYY8. | 07/28/13 |
YYMMDD6. | 130728 | YYMMDD8. | 13/07/28 |
DDMMYY8. | 28072013 | DDMMYY10. | 28/07/2013 |
MMDDYY8. | 07282013 | MMDDYY10. | 07/28/2013 |
YYMMDD8. | 20130728 | YYMMDD10. | 2013/07/28 |
DATE7. | 28JUL13 | MONYY5. | JUL13 |
DATE9. | 28JUL2013 | MONYY7. | JUL2013 |
3 变量输入和输出格式
输入格式是给SAS读的,输出是给使用者读的。
变量类型 | 输入格式 | 输出格式 |
---|---|---|
数值型非日期型 | ||
数值型日期型 | ||
字符型 |
- 1 输入格式
见上述。使用input或input搭配informat。不想改变输入值,不要在输入格式中定义宽度。
data test;
/*使用input*/
input date yymmdd10.;
/*使用input+informat*/
input date;
informat date yymmdd10.;
- 2 输出格式
大致同输入格式。在data步,在input语句与cards之间使用format。
data test;
input x;
format yymmdd10.;
cards;
20100101
20111103
;
字符型
完整的格式应该是$ < w. >。
必须在变量名后加"$";w表示字节数(1个中文占2个字节)。
输入格式 | 输出格式 |
---|---|
$ < w. > | $ < w. > |
默认只读取前8位,超出8位必加上“w.” | 不限制输出位数 |
data city;
input city$ code$;
format city $4. code $2.; /*city的输出格式为字符型且字节数为4;code的输出格式为字符型且字节数为2*/
cards;
北京市 110000
天津市 120000
上海市 310000
;
proc print;
run;
结果为:
Obs | city | code |
---|---|---|
1 | 北京 | 11 |
2 | 天津 | 12 |
3 | 上海 | 31 |
数值型
输入格式 | 输出格式 | 含义 |
---|---|---|
w.d | w.d | 总位数w,其中小数点后位数d(小数点算1bit) |
commaw.d | + 整数部分加逗号(逗号算1bit) | |
percentw.d | + 百分数形式(%算3bit) |
w.d的理解:
- w是指数值从左到右读取的位数,包括小数点、逗号!
- d是指小数点后的位数!
- 整数若不带有小数点,则在读取时被认为小数部分。
commaw.d 可将数值的整数部分自右向左每三位用逗号隔开,当数值位数较多时,这是比较标准的表示方式。
data wt;
input num cost;
format num 5.2 cost comma12.1; /*num共5位其中2位小数;cost共12位其中1位小数,且用逗号每3位分隔*/
cards;
50 10205600
45 9580000
;
proc print;
run;
例如,输出格式为comma7.1时。
输入 | 输出 |
---|---|
111 | 111.0 |
1111 | 1,111.0 |
11111 | 11111.0 |
111111 | 111111 |
1111111 | 1111111 |
11111111 | 1.111E7 |
日期型
日期有两种类型:数字、日期格式。
输入格式 | 输出格式 |
---|---|
日期格式 | 日期格式 |
分隔符 |
日期型变量输入格式与输出格式大致相同,但输出格式允许在宽度值前加一个字母,表示日期的分隔符号。但不能用于date7.或date9.等格式。
日期格式
日期格式 | 举例 | 日期格式 | 举例 |
---|---|---|---|
DDMMYY6. | 280713 | DDMMYY8. | 28/07/13 |
MMDDYY6. | 072813 | MMDDYY8. | 07/28/13 |
YYMMDD6. | 130728 | YYMMDD8. | 13/07/28 |
DDMMYY8. | 28072013 | DDMMYY10. | 28/07/2013 |
MMDDYY8. | 07282013 | MMDDYY10. | 07/28/2013 |
YYMMDD8. | 20130728 | YYMMDD10. | 2013/07/28 |
DATE7. | 28JUL13 | MONYY5. | JUL13 |
DATE9. | 28JUL2013 | MONYY7. | JUL2013 |
分隔符号
字母 | 含义 | 日期输出格式 | 结果显示 |
---|---|---|---|
s | slash(/) | YYMMDDs8. | 13/07/28 |
d | dash(-) | YYMMDDd8. | 13-07-28 |
p | point(.) | YYMMDDp8. | 13.07.28 |
c | colon(:) | YYMMDDc8. | 13:07:28 |
b | blank( ) | YYMMDDb8. | 13 07 28 |
n | nothing() | YYMMDDn8. | 20130728 |
自定义输入和输出格式:proc format
- 自定义值的内容的输入与输出格式 invalue 与 value
invalue 输入看“原值”
value 输出看“新值”
proc format;
invalue <$> variable_name range/value = self-defined value.../*自定义输入格式*/
value <$> variable_name range/value = self-defined value.../*自定义输出格式*/
picture module_name < range >;
原值 | 新值 | 语句 | |
---|---|---|---|
输入 | 字符型 | 数值型 | invalue grade "a"-"g"=1 other=2 |
输入 | 字符型 | 字符型 | invalue $grade "a"-"g"="fair" "o","u"="other" |
输入 | 数值型 | 数值型 | invalue lxfmt 1-4=same 99=.; 1-4则保持不变,99则改为缺失值 |
输入 | 数值型 | 字符型 | invalue $gender 1="male" 2="female" |
原值 | 新值 | 语句 | |
---|---|---|---|
输出 | 字符型 | 字符型 | value $grade "a"-"g"="fair" |
输出 | 字符型 | 数值型 | value $grade "a"-"g"="fair" "o","u"="other" |
输出 | 数值型 | 字符型 | |
输出 | 数值型 | 数值型 |
- 自定义值的形式的格式 picture
picture 格式名 原值=新格式(prefix="¥");/*prefix表示加前缀*/
proc format;
/*对所有数值,定义格式要求:前缀为¥,每满三位数加逗号“,”*/
picture gs1 low-high="0,000,000"(prefix="¥");
/**/
picture gs2 low-high="09.99%";
run;
data profit;
input profit prop;
format profit gs1. prop gs2.;
cards;
298000 16.72
458992 21.30
;
proc print;
run;
结果为:
Obs | profit | prop |
---|---|---|
1 | ¥298,000 | 16.72% |
2 | ¥458,992 | 21.30% |
说明一下,"09.99%"的理解是:
- 先对齐小数点;
- 再根据小数点前多少位数就保留多少位数
- 整数部分从个位开始,小数点前多少位就保留多少位数
- 倘若不只有一个小数点,那么先对齐最末尾的小数点;
- 末尾加上符号(不是把原值改为等值的百分数形式!!无论是什么符号都可以!!)
4 特殊变量的输入
给定宽度,是否取空格为字符
data test;
input id$8. gender$1. city$7.;
cards;
12345678 m beijing
;
proc print;
run;
所得结果为:
obs | id | gender | city |
---|---|---|---|
1 | 12345678 | m beiji |
原因是指定宽度后,空格也成为字符的一部分。修改方式如下:
-
需要指定多个变量的宽度
-
改变输入格式中的宽度
input id$9. gender$2. city$7.
-
改变变量的读取位置(+1表示往后1个字符读取)
input id$8.+1 gender$1.+1 city$7.;
-
利用冒号(:)来正确读取(冒号表示识别前后的空格是分隔符号,不作为字符内容;否则空格也是字符的一部分)
冒号(:)的作用是告诉SAS,如果要读取下一个数据,需要满足下面任一条件:
- 遇到空格;
- 指定的变量宽度已满;
- 数据行结束。
input id:$8. gender:$1. city:$7.;
-
-
数据集中有空格
&读取 空格作为字符的一部分,而<u>多个空格则作为分隔符</u>
(变量名后加 “&”。同时cards后的不同变量之间需要至少2个空格。)
data fh; input name&:$50. city&:$50.; /*变量名后加 $ */ cards; Peter Parker 山东省 蓬莱市 /*两个变量之间至少2个空格*/ Ross Geller 山东省 青岛市 市南区 ; proc print; run;
数据集中有缺失值
缺失值用 “. ”表示。
data fh;
input id day: yymmdd8. city:$20.;
format day yymmddp10.;
cards;
37 980515 .
. 120607 shanghai
39 . nanjing
;
proc print;
run;
结果为
obs | id | day | city |
---|---|---|---|
1 | 37 | 1998.05.15 | |
2 | . | 2012.06.07 | shanghai |
3 | 39 | . | nanjing |
有规律的变量
用do循环输入数据
data test;
do count=3 to 9 by 2;
<语句>
end;
run;
其中的语句若使用input,则必须加上output。
例如1-12月是连续加1的规律。
未使用do循环时:
data test;
input count time;
cards;
1 23
2 29
3 49
4 64
5 87
6 96
;
proc print;
run;
由于count具有加1的规律,使用do循环后:
data test;
do count=1 to 6; /*使用do循环输入count的值*/
input time;
output; /*必须*/
end; /*必须*/
cards; /*省略count的输入*/
23
29
49
64
87
96
;
proc print;
run;
是否换行输入
用@符号
-
@@与@符号的区别:
- @@强制保持当前记录,不管data步中有没有其他语句
- @如果data步中没有其他语句,就hold不住当前记录,仍然转到下一记录,如果有第二个input语句,就可以hold住当前记录,等待第二个input顺序读取
-
@@ 强行保持当前行。所输入数据均作为某一变量的值
- CASE 1——录入单一变量
data test; input weigh@@; cards; 1 2 3 4 5 6 ; proc print; run;
结果为:
Obs weigh 1 1 2 2 3 3 4 4 5 5 6 6
- CASE 2——输入列联表
| |吸烟(1)|不吸烟(2)|
| ---- | ---- | ---- |
| 男(1) |100 |150 |
|女(2)|10|140|
```sas
/*常规输入*/
data a;
input gender smoking;
cards; /*每一行表示一个个案的资料*/
1 2
2 1
1 1
1 1
...
;
proc print;
run;
/*用@@输入*/
data a;
do gender= 1 to 2;
do smoking= 1 to 2; /*先进行小循环,后进行大循环*/
input x@@; /*x为频数*/
output;
end;
end;
cards;
100 150
10 140
;
run;
```
结果:
| Obs | gender | smoking |
| ---- | ------ | ------- |
| 1 | 1 | 2 |
| 2 | 2 | 1 |
| 3 | 1 | 1 |
| 4 | 1 | 1 |
-
@ 保持当前行
data test; /*<几种不同的input方式>;*/ cards; 1 2 3 4 5 6 7 8 ; proc print; run; /*1*/ input x@@; /*2*/ input x; input y; /*3*/ input x@; input y; /*4*/ input x y;
结果分别为:
<1>通过@@强制将所有数据录入为值
Obs x 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 <2>x与y分别在两行,各取一个值
/*2*/ input x; input y;
Obs x y 1 1 5 <3>通过@保留原排列并认为第一、二列分别是x、y变量
/*3*/ input x@; input y;
Obs x y 1 1 2 2 5 6 <4>第一、二列分别是x、y变量
/*4*/ input x y;
Obs x y 1 1 2 2 5 6
输入重复测量数据
```sas
/*常规输入*/
data test1;
input id time score;
cards;
1 1 86
1 2 89
1 3 90
2 1 89
2 2 87
2 3 91
...
;
proc print;
run;
/*利用@符号输入*/
data test2;
input id@;
do time= 1 to 3; /*对于每个id,都有time从1到3取值*/
input score@@; /*对于每个id与time的组合,都有一个score相对应*/
output;
end;
cards;
1 86 89 90
2 89 87 91
...
;
proc print;
run;
```
产生新变量
新变量 = 表达式 或者 函数
算术运算符 | 比较运算符 | 逻辑运算符 |
---|---|---|
+ (加) | =(等于)、 ^=(不等于) | &或and(表示2个表达式同时成立) |
- (减) | >(大于)、 <(小于) | |或or(表示2个表达式任一成立) |
* (乘) | >=(大于等于)、 <=(小于等于) | |
/ (除) | in(范围)(属于其中)grade in(2,4,6)表示只要是grade为2、4、6中的其中一个就算符合条件 | |
** (幂次方) | dept not in(“A”, “B”)表示只要dept不是“A”或“B”就算成立 |
宽度限制
产生新变量前,对其进行宽度限定,使用length
data bonus;
input id g1 g2 bonus;
length g $6.; /*定义字符变量g的长度为6,若无该语句,则宽度受第一个值的影响*/
if g1>=70 and g2>=70 then g="合格";
else g="不合格";
if g="合格" then bonus=bonus*1;
else bonus=bonus*0.5;
cards;
1 67 74 10000
2 80 85 11000
3 89 87 11000
4 78 69 10000
;
proc print;
run;
无length语句:
Obs | id | g1 | g2 | bonus | g |
---|---|---|---|---|---|
1 | 1 | 67 | 74 | 5000 | 不合 |
2 | 2 | 80 | 85 | 11000 | 合格 |
3 | 3 | 89 | 87 | 11000 | 合格 |
4 | 4 | 78 | 69 | 5000 | 不合 |
有length语句:
Obs | id | g1 | g2 | bonus | g |
---|---|---|---|---|---|
1 | 1 | 67 | 74 | 5000 | 不合格 |
2 | 2 | 80 | 85 | 11000 | 合格 |
3 | 3 | 89 | 87 | 11000 | 合格 |
4 | 4 | 78 | 69 | 5000 | 不合格 |
5 数据集的导入和导出
6 建立和调用永久性数据集
SAS数据都是存放在资源管理器的逻辑库中。逻辑库中有SAS自带的6个文件夹,用来存放不同类型的数据。
理论上,我们在用data语句起名字时,还需要告诉SAS建立的数据集是放在哪个文件夹里。如,data sasuser.fh;表示建立数据集fh,放在sasuser这个文件夹,再如data work.fh;表示建立数据集fh,放在work这个文件夹。
SAS默认,如果data语句中没有加文件夹名字,就是默认为存放到临时文件夹work中,也就是说,data fh;与data work.fh;是完全等同的。当关闭sas时work内的数据集将清空。
建立永久性数据集
相当于把建立的数据集存放到硬盘的一个文件夹中。具体主要包括三个步骤:
- 在电脑硬盘建立一个文件夹,准备用来存放数据集;
- 在SAS的资源管理器中也新建一个文件夹,起个自己喜欢的英文名字;
- 把这两个文件夹关联起来。
方式一:菜单中新建
[1]在本地硬盘建立一个文件夹作为数据集存放处(假设路径为g盘目录下的mysasfile文件夹)
[2]逻辑库处右键新建新库并命名(假设是mydir),路径浏览选择上述文件夹
[3]编辑器处添加数据集
data mydir.test; /*在mydir库中添加名为test的新数据集*/
input id day: yymmdd8. city:$20.;
format day yymmddp10.;
cards;
370685 980515 shandong
;
run; /*运行后,在g盘目录下的mysasfile文件夹中会出现test数据集*/
方式二:编辑器中新建,并与逻辑库关联
[1]同上
[2]编辑器中新建新库,并添加数据集
libname mydir "g:\mysasfile"; /*新建名为mydir的新库,并与路径中的文件夹相关联*/
data mydir.test; /*在mydir库中添加名为test的新数据集*/
input id day: yymmdd8. city:$20.;
format day yymmddp10.;
cards;
370685 980515 shandong
;
run; /*运行后,在g盘目录下的mysasfile文件夹中会出现test数据集*/
方式三:编辑器中新建
data "g:\mysasfile\first";/*在g:\mysasfile\中新建一个名为first的数据集*/
input id day: yymmdd8. city:$20.;
format day yymmddp10.;
cards;
370685 980515 shandong
;
run;
调用永久性数据集
调用硬盘上的SAS数据集
[1]首先要知道硬盘上的文件夹位置及名称
[2]]利用libname语句读取相应位置的文件夹中的文件
libname mydir "g:\mysasfile";
proc print data= mydir.test;
run;