SAS數據清洗:
由於SAS數據集之間的關系一般不會用到,只是在proc sql中有所涉及,至今尚未運用過用於數據分析,所以在這里只講單個數據集的處理。
在proc sql中我們可以看到:在定義數據集時涉及到字段名,字段屬性,字段標簽這三個最常用。我們在數據清洗時涉及到的數據集字段的處理,主要也就是圍繞着字段名、字段屬性和字段標簽來進行處理。(對數據集結構的處理也就是對字段的增刪改)
修改數據集名稱和標簽(label)
增加字段很簡單,只需要在data步新建一個變量,對變量進行賦值即可。
刪除變量可以使用drop和keep二者二選一。
下面談一下最復雜的修改字段:
修改字段名最簡單復雜的方法可以利用增加字段和刪除字段二者結合。然后就是用sas中的rename關鍵字進行處理,格式為rename=(原字段名=新字段名)。
修改字段的標簽:(定義label attrib label 變量名=label名)
修改使用modify 數據集名;label 變量名=label名。其中modify可以用於修改rename format和label。
修改sas的數據類型。
在sas中只有兩種數據類型:數值型和字符型。日期在sas中存儲形式是數值型,只是在顯示時使用日期的format顯示。
所以主要就是涉及到數值型和字符型之間的轉換
數值轉換為字符:
data;
x=2557898;
y=put(x, $8.);
put y;
run;
字符轉換為數值:
data;
x=2557898;
y=put(x, 8.); /* y=x-0;*/
put y;
run;
數值型和日期型之間的轉換主要就是利用日期的format,進行格式化的輸入和輸出。
SAS的日期時間都是數字型的,以便於計算。有各種格式可以從數值轉變為字符型。1960-01-01是日期的開始,SAS的日期是0. 之后每天加一。1960-01-02的值為1. 1959-12-31的值為-1. 以此類推。時間是一秒為單位計算。從0(00:00:00)到86400(24:00:00)。每加一秒數值加一。
常用的日期時間轉換的function如下:
data _null_;
a=mdy(12,31,1959);
b='02jan1960'd;
c='24:00:00't;
d='00:00:00't;
e='31dec90:5:00:00'dt;
format e datetime18.;
put a= b= c= d= e=;
run;
a=-1 b=1 c=86400 d=0 e=31DEC90:05:00:00
data _null_;
x=1;
format x ddmmyy10.;
put x= ;
run;
output:
x=02/01/1960
字符串的處理:
對於所有的數據的處理無外乎增刪改查,雖然查在最后,但查是我們應該做的第一件事。
查找:既對字符串的切片,查找出任何位置任意長度的子字符串。
1.獲得字符串的長度:length(strings)
2.獲得字符串中某子字符的索引:index(s,s1) .s1在s中出現的位置,可以用於分割符的定位。
3.從固定的位置開始獲得固定長度的字符串:substr(s,p,n). 從字符串s中的第p個字符開始抽取n個字符長的子串.
4.scan函數:scan(string,i,"char") 表示從字串string中以char為分隔符提取第i個字串。其中char可以是多個字符組合。
如:data work.test;
Title = 'A Tale of two Cities,Charles j.Dickens';
Word = scan(title,6,' ,');
put Word;
run;
output:Word=Charles
以下的例子很疑惑:
data a;
arg='abcdrf';
word=scan(arg,1);
put word=;
run;
output:word=abcdrf
很多資料顯示這個的結果應該是word=a,但實驗結果卻是word=abcdrf,不明白是哪里不同?
data a;
arg='ABC.DEF(X=Y)';
word=scan(arg,2);
put word=;
run;
output:word=DEF
data a;
arg='ABC.DEF(X=Y)';
word=scan(arg,3);
put word=;
run;
output:word=X=Y
data a;
arg='ABC.DEF(X=Y)';
word=scan(arg,2,'.');
put word=;
run;
output:word=DEF(X=Y)
總結sas中scan函數在沒有定義分隔符的情況下會有默認分隔符(已知:空格 . , ()等,可能所有的符合都是),在定了分割符后僅以此分隔符為分割。Scan中的第二個變量即數字為字符串被分割成多個子字符串后,所要查找的子字符串的索引(索引從1開始)。
5.Find函數:Pos=find(Text,'US','i',5),是要從第5個字符起找出US在源字符串Australia, US, Denmark中的起始位置,並且忽略大小寫。
find函數中四個參數,Text不用說,代表源字符串,如果直接引用的話需要用引號括起來;US,代表將要查找的字符,加引號;i,在這里表示忽略大小寫;5,表示從第5個字符開始查找。
Notes:不管起始位置是多少,返回的位置數值始終是在源字符串中的位置。
6.Substr函數:(修改函數)
data _null_;
x=12345;
y=substr(x,1,2);
y1=substr(x,9,2);
z=substr(left(x),1,2);
put x= y= y1= z=;
run;
Output:x=12345 y= y1=23 z=12
y為空的原因是x為數值型。y1為字符型,9在這里可能有特殊的含義。Left(x)后會轉化為字符型。
字符替換(即所謂的右等):
data wb;
a='KIDNAP';
substr(a,1,3)='CAT';
put a;
run;
輸出結果:CATNAP
另外一種情況:
data wb;
a='KIDNAP';
substr(a,1,4)='CAT';
put a;
run;
結果為:CAT AP
7. TRANWRD函數:(修改函數)
data convert;
input @1 address $20. ;
*** Convert Street, Avenue and
Boulevard to their abbreviations;
Address = tranwrd(Address,'Street','St.');
Address = tranwrd(Address,'Avenue','Ave.');
Address = tranwrd(Address,'Road','Rd.');
datalines;
89 Lazy Brook Road
123 River Rd.
12 Main Street
;
8.compress函數:(刪除函數)
Compress(String, characters-to-remove, optional-modifiers)
optional-modifiers:
- a 大寫 或小寫字母
- d 數值(dignits)
- i 忽略大小寫
- k 保留列表字符串,而不是去掉
- s 空間(blank,tabs,if,cr)
- p 標點符號
例子:僅保留數字。
data Units;
input @1 Wt $10.;
Wt_Lbs =
input(compress(Wt,,'kd'),8.);
if findc(Wt,'K','i') then
Wt_Lbs = 2.2*Wt_Lbs;
datalines;
155lbs
90Kgs.
;
ouput:Wt_Lbs =155 198(英鎊)
字符串的連接有cat和’||’兩個:
data cat_catx;
length v_cats $6. v_catx $16.;
v_str1='CHI';
v_str2=' RAN';
v_str3='56789';
v_cats=cats(v_str1,v_str2);/*cats函數首先去掉每個要連接字符串的首尾空格*/
v_catx=catx('/',of v_str1-v_str3);/*catx函數也去掉每個要連接字符串的首尾空格,並且會在每個字符串之間插入分隔符號*/
run;
cats和count組合:
data Survey;
input (Q1-Q5)($1.);
Num = countc(cats(of Q1-Q5),'y','i');
datalines;
yynnY
nnnnn
;
總結:通過length,substr(left=),index find,scan函數組合我們可以實現對字符串的切片。
通過substr和tranwrd可以實現對字符串的修改。通過compress可以實現對字符串內部的刪除,也會更改的一部分