SAS Base Programming · 35-40%
出題比率が最も大きい領域。並べ替え、条件分岐、属性変更、累計、関数、型変換、DO ループ、転置、マクロ変数をまとめて固めます。
試験対策ハブ · 詳細項目
01
PROC SORT は、BY 処理、マージ、レポートの前提になります。元データを残すなら OUT= を使います。
data= は入力データセット、out= はソート後に作るデータセットを指定する。by customer_id order_date; は、顧客 ID、日付の順で並べ替える。nodupkey は、BY 変数の値が重複する行を落とす。proc sort data=cert.orders out=work.orders_sorted; by customer_id order_date; run; proc sort data=work.orders_sorted out=work.unique_customers nodupkey; by customer_id; run;
NODUPKEY は BY 変数が同じ行の重複を落とします。行全体が完全一致する重複と混同しないようにします。
02
条件に応じた変数作成や再分類は頻出です。複数ステートメントを条件付きで実行する場合は DO と END でまとめます。
length は文字変数の長さを、代入より前に決める。if ... then は条件に合う場合だけ代入する。else if は前の条件に合わなかった場合だけ次を判定する。do; ... end; は複数のステートメントを 1 つの条件にまとめる。data work.orders_flagged;
set work.orders_sorted;
length amount_band $ 8 status $ 12;
if amount >= 10000 then amount_band = "High";
else if amount >= 3000 then amount_band = "Middle";
else amount_band = "Low";
if missing(customer_id) then do;
status = "Review";
review_reason = "Missing ID";
end;
else status = "OK";
run;
03
文字変数の長さは、最初に現れた定義で決まります。代入より前に LENGTH を置く癖をつけると、値の切り詰めを防げます。
length region_group $ 12; は文字変数の長さを 12 バイトにする。rename=(old_region=region) は読み込み時に変数名を変える。label は変数の説明、format は表示形式を指定する。in (...) は、値が指定リストに含まれるかを判定する。data work.orders_clean;
length region_group $ 12;
set work.orders_flagged(rename=(old_region=region));
label amount = "Order Amount"
order_date = "Order Date";
format amount comma12. order_date yymmdd10.;
if region in ("Tokyo", "Kanagawa", "Chiba", "Saitama") then region_group = "Kanto";
else region_group = "Other";
run;
Missing Values
数値計算では、欠損値の扱いがロジックエラーになりやすいです。+ 演算子と SUM 関数、SUM ステートメントの違いを意識します。
total_operator = a + b; は通常の足し算で、欠損の影響を受ける。sum(a, b) は非欠損値を合計する関数。running_total + a; は SUM ステートメントで、前行までの値を保持して累計する。datalines; は例示用の小さな入力データをコード内に置く。data work.missing_practice; input a b; total_operator = a + b; total_function = sum(a, b); running_total + a; datalines; 10 5 . 7 3 . ; run;
a + b は、どちらかが欠損なら結果も欠損になりやすい。sum(a,b) は、欠損を無視して非欠損値を合計する。running_total + a; は SUM ステートメントで、値を自動的に保持する。RETAIN を疑う。SUM 関数を使う。04
グループごとの小計や累計は、DATA ステップの核です。BY 変数でソートし、グループの先頭で初期化し、最後で出力します。
proc sort ... by customer_id order_date; で顧客別・日付順に並べる。by customer_id; は DATA ステップ内でグループ境界を使う宣言。first.customer_id で顧客ごとの初期化を行う。total_amount + amount; は合計を保持しながら加算する。last.customer_id の行だけ output して、顧客ごとに 1 行へまとめる。proc sort data=work.orders_clean out=work.orders_by_customer;
by customer_id order_date;
run;
data work.customer_summary;
set work.orders_by_customer;
by customer_id;
if first.customer_id then do;
total_amount = 0;
order_count = 0;
first_order = order_date;
end;
total_amount + amount;
order_count + 1;
if last.customer_id then do;
last_order = order_date;
output;
end;
format first_order last_order yymmdd10. total_amount comma12.;
keep customer_id total_amount order_count first_order last_order;
run;
BY Groups
first.customer_id と last.customer_id は、BY グループの始まりと終わりを示します。複数の BY 変数を使うと、どの単位で初期化するかが得点差になります。
by region customer_id order_date; は、地域、顧客、日付の順に並べる。by region customer_id; は、地域内の顧客単位で境界を作る。first.customer_id で顧客ごとに初期化し、last.customer_id で顧客ごとの結果を出す。proc sort data=work.orders_clean out=work.orders_by_region_customer;
by region customer_id order_date;
run;
data work.region_customer_summary;
set work.orders_by_region_customer;
by region customer_id;
if first.customer_id then do;
customer_total = 0;
customer_count = 0;
end;
customer_total + amount;
customer_count + 1;
if last.customer_id then output;
keep region customer_id customer_total customer_count;
run;
by region customer_id; の場合、顧客単位の集計なら first.customer_id で初期化します。地域全体の集計なら first.region を使うため、問題文の「単位」を先に確認します。
05
関数は範囲が広いので、試験ガイドにある代表関数をタスク別に覚えます。型変換は INPUT と PUT を明示的に使います。
+ とは欠損時の挙動が違う。scan と substr は、文字列から必要部分を取り出す。put(order_date, yymmddn8.) は日付値を文字列に変換し、後続の substr で年月を抜き出す。round(amount, 100) は 100 単位で丸める。intck は期間数、intnx は指定期間だけ進めた日付を求める。data work.function_practice;
set work.orders_clean;
product_prefix = scan(product_code, 1, "-");
year_month = substr(put(order_date, yymmddn8.), 1, 6);
amount_round = round(amount, 100);
months_from_order = intck("month", order_date, today());
next_month_start = intnx("month", order_date, 1, "b");
char_amount = put(amount, comma12.);
num_amount = input(char_amount, comma12.);
run;
Conversion
SAS は必要に応じて自動変換を行いますが、ログに NOTE が出て、想定外の欠損や比較ミスにつながることがあります。試験では明示変換を書けることが重要です。
input(amount_char, comma12.) は、文字の金額を数値に変換する。put(order_date, yymmn6.) は、数値の日付値を年月文字列に変換する。format amount_num comma12.; は、数値の保存値は変えず表示だけ整える。data work.converted; set work.orders_clean; amount_num = input(amount_char, comma12.); order_month = put(order_date, yymmn6.); format amount_num comma12.; run;
INPUTPUT06
DO ループは繰り返し処理、PROC TRANSPOSE はデータの縦横変換、マクロ変数はプログラム保守に使います。
%let はプログラム中で再利用する値をマクロ変数に入れる。do month = 1 to 12; は 1 から 12 まで繰り返す。mdy(month, 1, &target_year.) は月・日・年から SAS 日付値を作る。proc transpose の var は転置する値、id は列名になる値、by はグループ単位を指定する。%let target_year = 2026;
%let outlib = work;
data &outlib..monthly_targets;
do month = 1 to 12;
target_date = mdy(month, 1, &target_year.);
output;
end;
format target_date yymmdd10.;
run;
proc transpose data=work.sales_long
out=work.sales_wide(prefix=month_)
name=source_variable;
by customer_id;
id month;
var amount;
run;
PROC TRANSPOSE で BY を使う場合、対象データは BY 変数でソート済み、または適切にインデックス化されている必要があります。
&outlib..monthly_targets のようにドットが 2 つ見えるのは、1 つ目がマクロ変数名の終端、2 つ目がライブラリとメンバ名の区切りです。