SAS Base
- Base言語活用のポイント
- dataステップ内関数(文字列の情報取得)
- dataステップ内関数(文字列の編集)
- dataステップ内関数(その他)
- グローバルステートメント
- procステップ
- データセットオプション
- 外部ファイルを読み込む
- Excelファイルを読み込み、データセット化するマクロ
- 外部CSVファイルをproc importプロシジャで読み込み、データセット化する
- 外部CSVファイルをdataステップで読み込み、データセット化する
- 外部ファイルの読み込み(proc import)
- infileステートメント
- 制御文字を文字リテラルで扱う
- proc sql内で「欠損値かどうか」の条件を指定する
- dataステップ内で「欠損値かどうか」の条件を指定する
- 指定の文字列をN回繰り返した文字列を用意する
- proc sqlでのサブクエリの使用
- dataステップ内のset句で読み込んだデータセットに、行番号を付与する
- データセットの列の重複を削除して取得
- ログにテキストや変数の内容を出力する
- リスト文字列などを指定の区切り文字で区切り、n番目の要素を取り出す
- データセットの内容はいじらないが、dataステップ内で使用できる関数を使用したいとき
- リスト文字列の要素でループする
- proc sqlで取得したクエリ結果を、区切り文字で結合しマクロ変数に代入する
- SASデータセットの各行の値を(任意の区切り文字)で結合し、文字列としてマクロ変数に格納する
- 外部ファイルにテキストを出力する
- 文字列「yyyymmdd_hhmmss」を得る
- よく使うシステムオプション
- リスト文字列の要素でループする
- 文字列の長さに合わせてブロックコメントを生成する
- proc sqlで取得したクエリ結果を、区切り文字で結合しマクロ変数に代入する
- ods htmlステートメント
- 日時データの利用
- dataステップ内関数の使用例
- ソート済のデータセット列について、その値をもつ「最初の行」や「最後の行」だけで処理を行う
- CASL
Base言語活用のポイント
- マクロの世界とdataステップの世界を分けて考える
- シングルクォートとダブルクォートの違いをしっかり押さえる
- ステートメント、ステートメントに紐づくオプション、データセットに紐づくオプションをしっかり区別する
- dataステップが実際に動くときのなんとなくのイメージを掴む
- 記述するのは列名とかだけであるが、実際の処理では1行ずつループされる
- 他のプログラミング言語とは異なり、「マクロを呼び出した箇所にマクロの定義内容を出力する」性質を持っている。そのため、カンマ区切りの内容だけを持つマクロを定義し、proc sqlのselect句の指定部分に用いるなどの芸当が可能。
dataステップ内関数(文字列の情報取得)
count関数
文字列Xに存在する'A'の個数をカウントする。count(X, 'A')
length関数
文字列Xの長さを1バイト単位で取得する。length(X)
klength関数
文字列Xの長さを文字数単位で取得する(1バイト文字も2バイト文字も長さ1としてカウント)。klength(X)
index関数
文字列Xの最初の'ABC'の開始位置を取得する。index(X, 'ABC')
substr関数
文字列Xの部分文字列(5~8文字目)を取得する。substr(X, 5, 8)
dataステップ内関数(文字列の編集)
cat関数
文字列を結合する。cat(X, Y, ...)
cats関数
文字列の先頭・末尾のスペースを取り除き、結合する。cats(X, Y, ...)
catx関数
文字列の先頭・末尾のスペースを取り除き、指定した区切り文字で結合する。catx('区切り文字', X, Y, ...)
tranwrd関数
- 文字列X内の'ABC'を'XYZ'に置換する。
tranwrd(X, 'ABC', 'XYZ')-
tranwrd(変換したい文字列, 検索文字列, 置換する文字列) - TRANWRD関数 - SAS® Help Center
-
compress関数
文字列Xから、指定した文字Aをすべて取り除く。除去対象の文字列を指定しない場合は、スペースをすべて取り除く。compress(X, 'A')
trim関数
文字列の末尾のスペースを取り除く。trim(X)
strip関数
文字列の先頭および末尾のスペースを取り除く。strip(X)
dataステップ内関数(その他)
fileexist関数
- 外部ファイルの存在を確認する。存在する場合は
1、存在しない場合は0が返却される。
グローバルステートメント
filenameグローバルステートメント
- 外部ファイル(.csvや.xlsxなど)がある場所に「ファイル参照名」を付ける(パス情報を特別な変数に入れる)
filename test_data = 'C:\SAS_Study\test.csv';
proc import datafile=test_data out=work.test dbms=csv replace;
getnames = yes;
datarow = 2;
run;
xグローバルステートメント
- OSコマンドを実行する。
libnameグローバルステートメント
- SASデータセットが格納されるSASライブラリを定義する。
- データセット以外にも「SASエンジン」を指定することで、他のタイプのファイルへのアクセスを可能にすることもできる。
procステップ
proc sortステートメント
- データセットのソートを行う。
サンプル
proc sort data=sashelp.cars out=work.cars_sorted;
by Model;
run;
オブション
proc sortから;までの間にスペース区切りで記述する。
| オプション | 指定する内容 | 説明 |
|---|---|---|
| data= | データセット名 | ソート対象のデータセットを指定 |
| out= | データセット名 | ソートした内容を格納するデータセットを指定(指定しない場合は上書きされる) |
| nodupkey | - | 重複の削除を行う場合は指定 (キー変数について、重複するデータがあった場合は重複している2件目以降の行を削除する) |
プロシジャ内ステートメント
proc sort ~;からrun;までの行に記述する。
| ステートメント | 指定する内容 | 説明 |
|---|---|---|
| by | 列名 | ソートのキーとする列を指定 (列名の直前に descendingを付与することで、降順でソートできる) |
proc transposeステートメント
- データセットを転置する。
サンプル
proc sort data=sashelp.cars out=work.cars_sorted;
by Model;
run;
proc transpose data=work.cars_sorted out=work.cars;
by Model;
run;
オブション
proc transposeから;までの間にスペース区切りで記述する。
| オプション | 指定する内容 | 説明 |
|---|---|---|
| data= | データセット名 | 転置対象のデータセットを指定 |
| out= | データセット名 | 転置後のデータセットを指定 |
| prefix= | 文字列 | 転置後の列名に付与したい接頭辞を指定 |
| suffix= | 文字列 | 転置後の列名に付与したい接尾辞を指定 |
プロシジャ内ステートメント
proc transpose ~;からrun;までの行に記述する。
| ステートメント | 指定する内容 | 説明 |
|---|---|---|
| by | 列名 | 転置せずにそのまま残す列を指定 (byを使用する場合は、指定する列で事前にソートしておく必要がある) |
| var | 列名 | 転置する列を指定 |
| id | 列名 | 列の内容を「転置後の列名」として使用する列を指定 |
| idlabel | 列名 | 転置後の変数ラベルとして使用する変数を指定 |
proc importステートメント
- 外部ファイルを読み込む。
サンプル
proc import datafile='C:\SAS_Study\test.csv' out=work.test dbms=csv replace;
getnames = yes;
datarow = 2;
run;
filename input_data = 'C:\SAS_Study\input_data.txt'
proc import datafile=input_data out=work.test dbms=tab replace;
getnames = yes;
run;
オブション
proc importから;までの間にスペース区切りで記述する。
| オプション | 指定する内容 | 説明 |
|---|---|---|
| datafile= | ファイルパス or ファイル参照名 |
「入力ファイルのフルパス」または「filenameステートメントで定義したファイル参照名」を指定 |
| out= | データセット名 | 転置後のデータセットを指定 |
| dbms= | データソース名 | 外部ファイルのデータの種類を指定 xlsx / csv / tab / dlm(delimiterステートメントと併用) |
| replace | - | 出力データセットを上書きする場合は指定 |
プロシジャ内ステートメント
proc import ~;からrun;までの行に記述する。
| ステートメント | 指定する内容 | 説明 |
|---|---|---|
| getnames= | yes / no | 列名情報をファイルから取得するかどうかを指定 |
| sheet= | Excelシート名 | 読み込むシート名を指定(dbms=xlsxの場合のみ有効) |
proc exportステートメント
- データセットを外部ファイルへ出力する。
サンプル
proc export data=sashelp.class outfile='C:\SAS_Study\class.csv' dbms=csv replace;
run;
proc export data=sashelp.class outfile='C:\SAS_Study\class.xlsx' dbms=xlsx replace;
sheet = class;
run;
オブション
proc exportから;までの間にスペース区切りで記述する。
| オプション | 指定する内容 | 説明 |
|---|---|---|
| data= | データセット名 | 出力対象のデータセットを指定 |
| outfile= | ファイルパス or ファイル参照名 |
「出力先ファイルのフルパス」または「filenameステートメントで定義したファイル参照名」を指定 |
| dbms= | データソース名 | 外部ファイルのデータの種類を指定 xlsx / csv / tab / dlm(delimiterステートメントと併用) |
| replace | - | 出力データセットを上書きする場合は指定 |
プロシジャ内ステートメント
proc export ~;からrun;までの行に記述する。
| ステートメント | 指定する内容 | 説明 |
|---|---|---|
| putnames= | yes / no | 列名情報をファイルに書き出すかどうかを指定(デフォルトはyes) |
| sheet= | Excelシート名 | 読み込むシート名を指定(dbms=xlsxの場合のみ有効) |
proc univariateステートメント
- 各種統計量を算出し、レポートを出力する。
proc univariate data=sashelp.class normal plot;
var height;
output out=work.result n=n mean=mean std=std median=median;
run;
データセットオプション
データセットオプションの概要
- dataステップのsetステートメントなどで、データセット名の直後に
データセット名(~~~)のように記述し、利用する。- 複数のオプションを指定する場合はスペースで区切る。
- カテゴリ別のデータセットオプション - SAS® Help Center
data work.test;
set sashelp.class(keep=Name Height Weight where=(Height>60 and Weight>100));
run;
keep=データセットオブション
保持したい列名をスペース区切りで記載する。ここに記載されていない列はそもそも読み込まれないため、dataステップなどで使用不可となる。
drop=データセットオプション
除去したい列名をスペース区切りで記載する。ここに記載した列はそもそも読み込まれないため、dataステップなどで使用不可となる。
where=データセットオプション
https://documentation.sas.com/doc/ja/pgmsascdc/v_061/ledsoptsref/p0ny9o8t8hc5zen1qn3ft9dhtsxx.htm
データセット行の取得条件を指定する。
条件部分は()で括り、where=(Height>60 and Weight>100)のように記述する必要がある。
(keep=やdrop=の後にwhere=が処理される)
data work.test;
set sashelp.class(where=(Height>60 and Weight>100));
run;
rename=データセットオブション
データセットの列名を異なる列名で読み込む。rename=(name1=new_name1 name2=new_name2)のようにセットで指定する。(keep=やdrop=の後にrename=が処理される)
data work.test;
set work.table1(rename=(name1=new_name1 name2=new_name2));`
run;
外部ファイルを読み込む
Excelファイルを読み込み、データセット化するマクロ
-
proc importを使用する。
%macro ImportExcel(i_file_path=, i_sheet_name=, ods_output_name=);
proc import datafile=&i_file_path out=&ods_output_name. dbms = xlsx replace;
getnames = yes;
sheet = &i_sheet_name.;
run;
%mend ImportExcel;
外部CSVファイルをproc importプロシジャで読み込み、データセット化する
proc import datafile='C:\SAS_Study\test.csv' out=work.work.test dbms=csv replace;
getnames = yes;
datarow = 2;
run;
filename input_data = 'C:\SAS_Study\input_data.txt'
proc import datafile=input_data out=work.test dbms= replace;
getnames = yes;
run;
外部CSVファイルをdataステップで読み込み、データセット化する
filename sample "C:\SAS_Study\test2.csv";
data work.test;
infile sample dim="," firstobs=2;
input id:$8. name:$32. class:8.;
run;
外部ファイルの読み込み(proc import)
サンプル
proc import datafile='C:\SAS_Study\test.csv' out=work.test dbms=csv replace;
getnames = yes;
datarow = 2;
run;
filename input_data = 'C:\SAS_Study\input_data.txt'
proc import datafile=input_data out=work.test dbms=tab replace;
getnames = yes;
run;
オブション
proc importから;までの間にスペース区切りで記述する。
| オプション | 指定する内容 | 説明 |
|---|---|---|
| datafile= | ファイルパス or ファイル参照名 |
「入力ファイルのフルパス」または「filenameステートメントで定義したファイル参照名」を指定 |
| out= | データセット名 | 転置後のデータセットを指定 |
| dbms= | データソース名 | 外部ファイルのデータの種類を指定 xlsx / csv / tab / dlm(delimiterステートメントと併用) |
| replace | - | 出力データセットを上書きする場合は指定 |
プロシジャ内ステートメント
proc import ~;からrun;までの行に記述する。
| ステートメント | 指定する内容 | 説明 |
|---|---|---|
| getnames= | yes / no | 列名情報をファイルから取得するかどうかを指定 |
| sheet= | Excelシート名 | 読み込むシート名を指定(dbms=xlsxの場合のみ有効) |
infileステートメント
- データセットとして読み込む外部ファイルの情報を指定する。
filename test_data "C:\SAS_Study\test2.csv";
data work.test;
infile test_data dim="," firstobs=2;
input id:$8. name:$32. class:8.;
run;
制御文字を文字リテラルで扱う
改行文字CR
'0D'x
改行文字LF
'0A'x
タブ文字
'09'x
proc sql内で「欠損値かどうか」の条件を指定する
whereステートメント内でis missing演算子を使用する。反転する場合はis not missingを使用する。
dataステップ内で「欠損値かどうか」の条件を指定する
missing(列名)を使用する。反転する場合はnot missing(列名)とする。
指定の文字列をN回繰り返した文字列を用意する
dataステップ内でrepeat(繰り返したい文字, N - 1);を使用する。もしくは N * '繰り返したい文字'とする。
proc sqlでのサブクエリの使用
- 通常のSQLのように記述できる。
dataステップ内のset句で読み込んだデータセットに、行番号を付与する
set データセット名 CUROBS=一時変数名で新しい列に行番号を挿入できる。
データセットの列の重複を削除して取得
proc sortおよびnodupkeyを使用する。
/* carsデータセットのMake列の内容を、重複削除して取得する */
proc sort data=sashelp.cars(keep=Make) out=work.cars nodupkey;
by logic_type;
run;
ログにテキストや変数の内容を出力する
- dataステップ内では
put、マクロ内では%putを使用する。 - データセット内の変数を出力する場合は、シングルクォートやダブルクォートで括る必要はなく、変数名をそのまま指定する。
- 複数の内容を連結して出力する場合、
putは半角スペースで並べて記載、%putは||やcats()で明示的に結合して記載する。 -
putでデータセットの列を並べて記載した際、不要な半角スペースが付与されてしまう場合は、列名の直後に+(-1)を記載しておく。(詳細はputステートメントのリファレンスに記載されている)
%let val = test;
%put &val.;
data _null_;
set sashelp.class;
put Name +(-1) ', ' Age ;
run;
リスト文字列などを指定の区切り文字で区切り、n番目の要素を取り出す
dataステップ内でscan(文字列, n, 区切り文字(指定しない場合はあらゆる文字列で分割する))を使用し、値を取り出す。
データセットの内容はいじらないが、dataステップ内で使用できる関数を使用したいとき
- 出力先データセット名に
_null_を指定する。
data _null_;
put 'ログ出力のテスト';
run;
リスト文字列の要素でループする
-
%do %whileなどを組み合わせる。
%macro LoopTest();
%let name_list = AAA BBB CCC DDD;
%let index = 1;
%let name = %scan(&name_list., &index., ' ');
%do %while(not %sysevalf(%superq(name) =, boolean));
%put &name.;
%let index = %eval(&index. + 1);
%let name = %scan(&name_list., &index., ' ');
%end;
%mend LoopTest;
proc sqlで取得したクエリ結果を、区切り文字で結合しマクロ変数に代入する
-
into: マクロ変数名 separated by '区切り文字'を用いる。- 複数列から出力する場合でもintoは1つだけ。マクロ変数名にコロンを前置する
- INTO句 - SAS® Help Center
proc sql noprint;
select Name, Age
into :name_list separated by ' ', age_list separated by ' '
from sashelp.class
where age > 12;
quit;
SASデータセットの各行の値を(任意の区切り文字)で結合し、文字列としてマクロ変数に格納する
-
retainやend = eofを活用する。
data _null_;
set work.input_table end = eof;
attrib
input_file_list length = $1000.
output_file_list length = $1000.
;
retain input_file_list output_file_list;
input_file_list = catx(' ', input_file_list, cats('input_', category, '.xlsx'));
output_file_list = catx(' ', output_file_list, cats('output_', category, '.csv'));
/* 最後まで行ったらマクロ変数に出力 */
if (eof) then do;
call symputx("input_file_list", input_file_list, 'G');
call symputx("output_file_list", output_file_list, 'G');
end;
run;
-
end=一時変数名最後の行を読み込んだ時、一時変数に「1」が入る -
_N_データステップの反復回数(処理中の行番号)が格納される -
cats(値1, 値2, ...)引数値の両端の半角スペースを除いて結合する
外部ファイルにテキストを出力する
-
filenameおよびfileステートメントを使用する。-
filename... 「SASファイル参照名」と「外部ファイルまたは出力デバイス」の関連付け・関連付けの解除を行う。 -
file... putステートメントの出力先ファイルを指定する。
-
data _null_;
filename OUTFILE "file_path";
file OUTFILE encoding="utf-8"; /* ファイル内容を空っぽにする */
run;
data _null_;
set sashelp.class;
file OUTFILE MOD; /* ファイルに追記する */
put Name;
run;
文字列「yyyymmdd_hhmmss」を得る
%local _timestamp;
data _null_;
call symputx("_timestamp", put(today(), yymmddn8.) || '_' || compress(put(datetime(), tod8.), ':'));
run;
よく使うシステムオプション
ログを簡素化する
option nosource nonotes;
-
nosource... ソースステートメント(実行しているSASコードの内容)をSASログに表示しないようにする -
nonotes... NOTEログを表示しないようにする(エラーメッセージや警告メッセージは変わらず表示される)
ログを詳細化する
option symbolgen mprint mlogic;
-
symbolgen... マクロ変数の置換結果を表示する -
mprint... マクロ実行時に行われるSASステートメントをログに出力する -
mlogic... マクロ変数の評価式やマクロの実行開始、終了をログに出力する
リスト文字列の要素でループする
-
%do %whileなどを組み合わせる。
%macro LoopTest();
%let name_list = AAA BBB CCC DDD;
%let index = 1;
%let name = %scan(&name_list., &index., ' ');
%do %while(not %sysevalf(%superq(name) =, boolean));
%put &name.;
%let index = %eval(&index. + 1);
%let name = %scan(&name_list., &index., ' ');
%end;
%mend LoopTest;
文字列の長さに合わせてブロックコメントを生成する
-
length()およびklength()を組み合わせ、マルチバイト文字を含めたいい感じの文字長を計算し、ブロックコメントを生成する。- 実行環境によってはうまくいかないこともある。
data _null_;
comment_text = strip(&comment_contents.);
comment_len = (length(comment_text) - klength(comment_text)) / 2 + klength(comment_text);
comment_line = '/*-' || repeat('-', comment_len - 1) || '-*/';
put comment_line;
put '/* ' "&comment_contents." ' */';
put comment_line;
run;
proc sqlで取得したクエリ結果を、区切り文字で結合しマクロ変数に代入する
-
into: マクロ変数名 separated by '区切り文字'を用いる。(複数列から出力する場合でもintoは1つだけ.マクロ変数名にコロンを前置する)
proc sql noprint;
select Name, Age
into :name_list separated by ' ', age_list separated by ' '
from sashelp.class
where age > 12;
quit;
ods htmlステートメント
- データセットやレポートをHTMLファイルへ出力する。
ods html file='C:\SAS_Study\class.html';
proc means data=sashelp.class;
run;
ods html close;
日時データの利用
data work.date_info;
now_datetime = datetime();
now_date = datepart(now_datetime);
now_time = timepart(now_datetime);
yyyymmddn = put(now_date, yymmddn8.); /* yyyymmdd(n:区切り文字なし) */
yyyymmddb = put(now_date, yymmddb8.); /* yyyymmdd(b:スペース区切り) */
yyyymmddc = put(now_date, yymmddc8.); /* yyyymmdd(c:コロン区切り) */
yyyymmddd = put(now_date, yymmddd8.); /* yyyymmdd(d:コロン区切り) */
yyyymmddp = put(now_date, yymmddp8.); /* yyyymmdd(p:ピリオド区切り) */
yyyymmdds = put(now_date, yymmdds8.); /* yyyymmdd(s:スラッシュ区切り) */
yyyymdd10 = put(now_date, yymmdd10.); /* yyyy-mm-dd */
ddmmmyyyy = put(now_date, date10.); /* ddmmmyyyy */
hhmmss = put(now_time, time.); /* hh:mm:ss */
year = year(now_date);
month = month(now_date);
day = day(now_date);
hour = hour(now_time);
min = minute(now_time);
second = second(now_time);
format until_time time8.;
until_day = input('20250101', yymmdd8.) - now_date;
until_sec = input('24:00:00', hhmmss8.) - now_time;
run;
dataステップ内関数の使用例
data work.test;
set sashelp.class;
height_cm = round(height * 0.0254, 0.01); /* inchをmに変換 */
height_str = put(height_cm, best8.); /* 数値を文字列に変換 */
height_str = tranwrd(height_str, '.', 'm'); /* 文字列を置換 */
height_str = compress(height_str); /* 空白を削除 */
name_height = cats(Name, '_', height_str, 'cm'); /* 文字列を結合 */
run;
ソート済のデータセット列について、その値をもつ「最初の行」や「最後の行」だけで処理を行う
- dataステップ内でbyステートメントを適用すると、byステートメントで指定した列ごとに「first.列名」および「last.列名」の列が生成される。
- 使用したいデータセット列は、
proc sortなどであらかじめソートしておく必要がある。 - SASによるBYグループの処理方法
- 使用したいデータセット列は、
- それぞれ、下記の値が格納されている。
- first.列名 ... byステートメントでグループ化された各行のうち、最初の行にのみ'1'が格納されており、それ以外は'0'
- last.列名 ... byステートメントでグループ化された各行のうち、最後の行にのみ'1'が格納されており、それ以外は'0'
- この変数を使用すると、「最初だけ処理、最後だけ処理」といった処理を行わせることができる。
-
first.column_nameやlast.column_nameを使用し、if文で分岐させる。
proc sort data=sashelp.fish out=work.fish_sorted;
by species;
run;
data work.fish;
set work.fish_sorted(where=(not missing(Weight))); /* 欠損値の行を削除 */
by species; /* species列でグループ化 */
/* 計算用の列を初期化 */
if first.species then do;
count = 0;
weight_sum = 0;
end;
/* グループ内の行について、件数と合計を計算 */
retain count weight_sum;
count = count + 1;
weight_sum = weight_sum + Weight;
/* 平均値を計算し、行を出力 */
if last.species then do;
weight_avg = round(weight_sum / count, 0.1);
output;
end;
/* 出力したい列を指定 */
keep species count weight_sum weight_avg;
run;
CASL
table.loadTableアクション
https://documentation.sas.com/doc/ja/pgmsascdc/v_061/caspg/cas-table-loadtable.htm
table.promoteアクション
https://documentation.sas.com/doc/ja/pgmsascdc/v_061/caspg/cas-table-promote.htm