SAS入門

# 目的
SASの簡単な操作と検索の目星がたてられるようにする。

### SASとは
データ解析や統計分析、グラフの作成などができるソフトです。
***

# SASの基本(制御構文など)
SASには大きく分けて2種類のブロックがある。

- data stepと呼ばれる、SQLでいうところのカーソルのような動きをするブロック
    - 正確にはPDV(プログラムデータベクトル)で調べるとよい
    - 簡単に言うとsetでデータを一行ずつ読み込んでいくような動きのこと
- プロシージャと呼ばれるproc XX ~;で始まるブロック
    - 分析をしたり、比較をしたり、SASが提供している便利な機能みたいなイメージ
    - proc sql;で大体やりたいこと終わる
    - proc formatも便利。値の変換とかで使う。

## 言葉の違い

- データセット = テーブル
- オブザベーション = レコード
- 変数 = カラム

***
### 制御構文
```SAS
libname ライブラリ名 'path'; *<------ライブラリの読み込み;


/* 複数行のコメントアウト。ctrl + (shift) + [/] で設定 */
* 一行のコメントアウト;
* sasは各行,処理ごとにセミコロンを忘れずに。;
* 大文字小文字区別しない。マルチバイトもいける;

data _null_; *<------データステップの始まりは出力データセット名, _null_だと出力データセットなし;
    set XXXX; *<------読み込みデータセット;

/* 基本的な関数や構文はデータステップ内で使う。*/
/* データステップ外で使うのはマクロ変数＆マクロ関数等々 */

/*******************************************************/
*分岐;
/*******************************************************/
   if a = b then do; *処理が複数行になるときはdoで終わらせる;
       処理
   end;
   else if a = c then do;
       処理
   end;

   sex_num = ifn(sex="女性",1,2);
   sex_char = ifc(sex="女性","F","M");

   select;
       when(a = b) x=1;
       when(a = c) x=2;
       otherwise x=3;
   end;
/*******************************************************/
*ループ;
/*******************************************************/
   do i = 3 to 10;
       処理
   end;

   array array_list var1 var2 var3;

   do over array_list;
      put array_list;
   end;

   do i = 1 to dim(array_list);
      put array_list[i];
   end;

run; *<---------------データステップの終わりはrunで締める;
```


### Tips：便利な関数
#### 数値のコントロール 
| 関数(例) | 出力結果 |
|:-|:-|
|```datepart('202-01-01:8:45'dt)```|SAS日時値から日付値にする `2021-01-01` |
|```min(1,3,9,10,11)```|最小値を返す `1`|
|```max(1,3,9,10,11) ```|   最大値を返す `11` |

#### 文字のコントロール 
| 関数(例) | 出力結果 |
|:-|:-|
|`first(“SAMPLE”)`|文字列の最初の一文字を返す `“S”`|
|`compress(“sample”,”sa”)`|指定した文字を削除 `“mple”` |
|`compress(“sample”,”sa”,”K”)` |指定した文字を保持 `“sa”`|
|`compress(“sample01”,,”KD”)`|数値だけを保持     `“01”`|
|`compress(“<=0.01”,”.”,”KD”)` |  数値とピリオドを保持 `“0.01”`| 
|`cats(“    TEST “,99) `|前後空白なしの文字列にする `“TEST99”`|
|`catx(“, ”,”SAMPLE”,”TEXT”)` |区切り文字で区切って連結 `“SAMPLE, TEXT”`
|`tranwrd(“Mrs.X”, "Mrs.", "Ms.")` | 文字列をすべて置き換える `“Ms.X” `
|`substr(“ABCDE”,3,2)` |文字列の一部を返す `“CD”`|
|`substr(“ABCDE”,3)`| 文字数を省略すると残りの文字 全てを返す `“CDE”` 
|`scan(“090-1234-5678”,1,”-“) `| n番目に区切られた文字返す `“090” `
|`upcase(“sample”)`|大文字にする `“SAMPLE”` |
|`lowcase(“SAMPLE”)`|小文字にする `“sample”` |
 

#### 変数の型のコントロール
| 関数(例) | 出力結果 |
|:-|:-|
|`put(‘2021-01-01’dt,yymmdd10.) `|数値→文字値へ変換 
|`input(‘2021-01-01’,yymmdd10,) `|文字値→数値へ変換 
|`input(val, ?? best.) `|`??`をつけると無効なデータの エラーを無視して強制変換 


#### 条件分岐 
| 関数(例) | 出力結果 |
|:-|:-|
|数値 ：`ifn(条件,true,false)`, 文字値：`ifc(条件,true,false)` |プログラムのインデントをきれ いに揃えられるのでおススメ |


#### 欠損値 
| 関数(例) | 出力結果 |
|:-|:-|
数値 ：`nmiss(.,1,2,3,.)` |欠損値の数を返す `2`
`nmiss(1,2,3,4,5)`|欠損が一つもないとき `nmiss(1,2,3,4,5)=0(つまりfalse)` 
文字値：`cmiss(“A”,”B”,”C”)`|欠損値の数を返す `0`
数値 ：`coalesce(., ., 1, 99, ., 5)`|最初の非欠損値を返す `1`
文字値：`coalescec(“”, “-”, “BC”)` |最初の非欠損値を返す `“-”` 

#### その他 
| 関数(例) | 出力結果 |
|:-|:-|
|`length(“ABCDEFG”) `|文字数を返す `7`|
|`index(“test_text01”, “text”)` |文字列を検索し,最初の文字の 位置を返す `6` (つまり`true`)|
|`prxmatch(‘/^.*/’,var)`,`prxchange(‘s/(\d)(.*)/$2/’,-1,var) `|正規表現を使いたいとき便利です→ https://jex.im/regulex/ |
|FLG2のみ`“Y”`それ以外は`N`と仮定 `whichc(“Y”,FLG1,FLG2, FLG3)`|第1引数に等しい文字値を検索 し、最初に一致した値のインデ ックスを返す`2`| |`whichn(1,0,0,0,1,0,99)`|`4`|
|`lag(value) `| LAG関数により保存されたn個 前の値|

***

### 外部ファイルの読み込み
```SAS
*エクセル;
proc import out=出力データセット datafile='パス/ファイル名.excel' dbms=excel replace;
 getnames =yes;
 datarow = 2;
 sheet = 'シート名';
run;
*proc importでCSVも読み込めるが、infile inputでも読み込める;
data sample;
 infile 'path/file_name.csv' dsd missover firstobs=2 lrecl=32767;*32767が最長レコード長;
 input 読み込み変数1 読み込み変数2 …;
run;
```
***

### 関数定義
```sas
*関数の定義;
proc fmcp outlib=work.func.user; *関数をどこに保存するか;
   function sig(num, digit) $20; *関数名と引数名;
　　   　/*処理*/
      return (rnd_txt); *戻り値;
   endsub*; *この関数の閉じタグ;
quit;

*呼び出しできるようにする;
options cmplib=work.func;
```
***

### call execute
引数を解決し、実行用に解決された値を次のステップ境界で発行する。

```sas
data _null_;
   call execute('実行したいプログラム'); /*文字列として与える*/
   call execute(%nrstr(%sample_macro(a,b))); /*マクロを入れ込むときは%nrstr()を活用する※1*/
run;
```
※1　%nrstrが必要な理由は、ステップ境界に達するまでsasステートメントが実行されないため、マクロ展開されるタイミングが想定と異なってしまう可能性が高いため。
***

## プロシジャ
***
### proc transpose
```SAS
*縦横の入れ替え;
proc transpose data=データセット out=出力データセット prefix=var;
by 　横;
id 　縦;
var 対象の値;
run;
```

### proc sort
``` sas
proc sort data XXX nodupkey out=out dupout=dup;
   by a b c;
run;
```

| 引数,option |  |
|:-|:-|
| data  | 読み込むデータ  |
| nodupkey | 重複を許容しない。最初にヒットしたものを残して、重複は削除する。nodupだと全変数を対象とする。|
|out|ソート実施後に保存するデータセット名。指定しないと、元のデータセットを上書きする|
|dupout|重複で削除されたものを保存するデータセット|

Tips: outには\_null_を指定することも可能
`proc sort data=xxx nodupkey out=\_null_ dupout=dup; by a b c; run;`とするとキーが重複して削除されたものだけがdupに格納され、元のデータセットも上書きされない。
***

### proc compare

```SAS
proc printto print='出力パス/出力ファイル名.lst' new; run;　
proc compare 
  base=ベースのデータセット 
  comp=比較データセット 
  out=差があったときに出力するデータセット outbase outcomp outnoequal;
run;
proc printto;
%put &sysinfo.; *この値が0であれば不一致箇所なし、1以上はそれぞれ対応するbitの内容が不一致である;
```

***

### マクロ
```sas
*マクロの文字列操作;
%sysfunc(tranwrd(%str(&macro_var.), %str( ), %str(, ))); *スペースをカンマに置換する;
*データセットの有無を確認する;
%sysfunc(exist(work.データセット名));
*workのPATH;
%sysfunc(pathname(work));

*マクロの定義;
%macro sample_macro(var1, var2, option1=N, option2=); *位置パラメータが先、初期値の設定もできる;
   /*何かしらの処理*/
%mend;

*マクロの呼び出し;
%sample_macro('aaa',1, option1=Y);
```
***
# 統計など
***
### クロス集計
```sas
proc freq data=対象データセット;
   tables 縦 * 横;
run;
```
***
### 基本統計量
代表値（データ全体を表す値：最大、最小、中央値他）や散布度（散らばりを表す値:範囲、分散、標準偏差）

```sas
proc summary data=対象データ;
where 条件;
class var1 var2;
output out=出力データセット名
       n(val)=n mean(val)=mean 略※;
run;
```
※ここではn, mean, std, median, min, max, q1, q3なども指定できる
***
### 幾何平均と信頼上限下限
幾何平均は変化率の平均を求めるときや、logの値が正規分布になるときに使う

```SAS
proc ttest data=sashelp.class dist=lognormal;
 var weight;
 ods output statistis = _out;
run;
```
***

### 2群の割合の差
イメージはこんな感じ↓

| / | 有効 | 無効 | 有効割合 |
|:-:|:-:|:-:|:-:|
| 薬剤A  |   |   |   |
| 薬剤B  |   |   |   |

```SAS
proc freq data=対象データ;
 tables exposure + response / riskdiff;
 weight count;
run;
```
***
# グラフや出力等
***
### 設定等
```SAS
ods rtf file = 'path/file_name.rtf' style = スタイルがあれば設定する nogtitle nogfootnote headery=上の余白(wordのヘッダー部分の高さの設定);
ods listing image_dpi = 300; *解像度;
ods graphics / reset =index imagename='画像の名前' imagefmt=png heignt=高さ width=幅 noborder noscale;
```
***
### 表を出力する
```SAS
proc report data=データセット split='|' /*折り返しの記号*/
    style(header) = {just = l} /*左寄せ*/
    style(column) = {just = c} /*中央揃え*/;
  /*このstyle()のところでfontやサイズ、罫線などいろいろ指定できる*/
  where 条件;
  columns ('大項目' ('中項目1'var1-var2) ('中項目2'var3-var4));
  define var1/display style(column) = {cellwidth=Xcm} '小項目1';
  define var2/display style(column) = {cellwidth=Xcm} '小項目2';
  define var3/display style(column) = {cellwidth=Xcm} '小項目3';
  define var4/display style(column) = {cellwidth=Xcm} '小項目4';
/*keyword: page(ページを変える) id(ページをまたがっても表示させる) order=data(並び順) borderbottomwidth(罫線) とかで検索する*/
  compute var1;
   何かしらの例外処理
  endcomp;
run;
```
***
### 散布図
***
### 箱ひげ図
***
### スパゲッティプロット
```SAS
/*対象データセットに縦横の変数を作成し、横軸でソートしておく。*/
proc sgplot data=対象データセット noborder nowall noopaque noautolegend;
 series x = 横軸変数 y = 縦軸変数 / name ='a' group =　グループ変数 
        lineattrs = (color = black pattern = solid);
 xaxis display = (nolabel noticks) values = (/*目盛りの刻み*/ 1, 2, 10, …) fitpolicy = none;
 yaxis label = 縦軸のラベル;
run;
```
***
### 生存曲線
***
### エクセル出力
```SAS
*エクセルを起動する;
options noxwait noxsync;
x 'start excel';
filename cmd dde 'excel|system';
*対象のファイルを開く;
data _null_; file cmd; put '[open("path/file_name.xlsx")]'; run;
*待機時間作ったほうがいいケースもある;
data _null_; rc = sleep(3); run;
*書き込む;
filename sheet dde 'excel|シート名!範囲';/*この範囲はr1c1方式で記載する*/
data _null_; set データセット; file sheet notab dsd dlm="09"x; put 変数1; run:
*保存したりシートを削除したり;
filename cmd dde 'excel|system';
data _null_; file cmd;
 put '[error(false)]'; *警告を出さない;
 put '[workbook.delete("削除シート名")]'; *シートを削除;
 put '[select("r1c1")]'; *セルを選択;
 put '[save.sa("path/file_name.xlsx")]'; *別名で保存;
 put '[close(true)]'; *閉じる;
 put '[quit()]';
run;
filename cmd clear;
```
***

# option
```SAS
*数値欠損のピリオドを表示しない;
option missing="";
*マクロを呼び出した時、ログに呼び出し内容を表示する;
option mprint;
*フォーマットが解決できなくてもデータセットを開けるようにする;
option nofmterr;
```
***
# 便利なSASHELP
| view名 | 内容 |
|:-|:-|
| Vcolmn  | 各データセットの変数情報(type, format, lengthとか)  |
| Vcatalg  | formatとか  |
| Vmacro  | マクロ変数  |
| Vmember  | ライブラリとデータセット名、PATH  |
| Vtable |  データセットの各種情報 |

# 大体ここみりゃわかる
https://sas-boubi.blogspot.com/

https://sas-tumesas.blogspot.com/

https://support.sas.com/documentation/cdl_alternate/ja/lestmtsref/68024/HTML/default/p08st7rzfn0dgin1fml8hq40hlho.htm