SASマクロ データの入出力

【SAS】テキストファイル(カンマ区切り、タブ区切り)の読み込み(INFILE、CSV、TAB)

1.タブ区切りの読み込み

・サンプルデータ

国勢調査令和2年人口集計.txt
tab
ちなみに、このサンプルデータは、政府統計e-Statから取得し、それを少し加工しています。
 

・展開例

ヘッダー部分の変数名を自動取得して読み込むパターンです。
自動取得っと言っても、文字変数が含まれる場合は引数charを指定する必要があります。
すべて数値変数であれば、引数charは省略しても大丈夫です。

%read_text(
	infile		=C:\Blog\SAS\read_text\国勢調査令和2年人口集計.txt,
	tab			=Y,
	headerobs	=1,
	firstobs	=2,
	char		=sex_label age_label area_label $10., 
	outdata		=list_population
);

tab_sasdata
 

2. ヘッダー無しカンマ区切りの読み込み

・サンプルデータ

国勢調査令和2年人口集計_ヘッダー無し.csv
csv_header_nashi
 

・展開例

・引数inputを指定するパターン

引数input(INPUTステートメント)で読み込む場合は、以下のようにコロン「:」を使用して読み込みます。
また、ヘッダー部分が無いので、引数firstobs=1を指定します。

%read_text(
	infile		=C:\Blog\SAS\read_text\国勢調査令和2年人口集計_ヘッダー無し.csv,
	tab			=N,
	input		=sex sex_label:$10. age age_label:$10. area area_label:$10. population,
	firstobs	=1,
	outdata		=list_population
);

 

・引数vnameとcharを指定するパターン

引数vnameを使用する場合、文字変数は引数charに指定して読込みます。

%read_text(
	infile		=C:\Blog\SAS\read_text\国勢調査令和2年人口集計_ヘッダー無し.csv,
	tab			=N,
	vname		=sex sex_label age age_label area area_label population,
	char		=sex_label age_label area_label $10., 
	firstobs	=1,
	outdata		=list_population
);

csv_header_nashi_sasdata
 

3.数値にゴミを含むタブ区切りの読み込み

・サンプルデータ

国勢調査令和2年人口集計_数値にゴミあり.txt
tab_gomi
 

・展開例

数値として読み込みたいカラムにハイフン「-」やエラー値「#N/A」などのゴミが含まれている場合は、先に入力形式を作成し、引数inputで読み込みます。

proc format;
	invalue error
		"-"		= .
		"#N/A"	= .
	;
run;

%read_text(
	infile		=C:\Blog\SAS\read_text\国勢調査令和2年人口集計_数値にゴミあり.txt,
	tab			=Y,
	input		=sex sex_label:$10. age age_label:$10. area area_label:$10. population:error.,
	firstobs	=2,
	outdata		=list_population
);

以下のように、ハイフン「-」だった変数値が欠損値に置換されています。
tab_gomi_sasdata
 

4. 参考プログラム

以下は、参考プログラムになります。
右上のコピーボタンを押せば、プログラム全体をコピーできます。

%macro read_text(infile=, tab=, headerobs=1, firstobs=2, input=, vname=, char=, outdata=);
%put --------------------------------------------------;
%put read_text;		/*テキストファイル(カンマ区切り、タブ区切り)の読み込み*/
%put &=infile;		/*テキストファイル名をフルパスで指定する*/
%put &=tab;			/*Yを指定した場合はタブ区切りで読込み、それ以外はカンマ区切りとして読込む*/
%put &=headerobs;	/*ヘッダー部分の行番号を指定(既定値=1)*/
%put &=firstobs;	/*データ部分の開始行番号を指定(既定値=2)*/
%put &=input;		/*変数をINPUT文で読込む場合に指定し、その場合はvnameとcharの指定は不要となる*/
%put &=vname;		/*変数名を自動取得しない場合に指定し、文字変数が含まれる場合はパラメータcharの指定は必須*/
%put &=char;		/*読込むデータに文字変数が存在する場合、「変数名(複数指定可) $〇〇.」で指定する*/
%put &=outdata;		/*出力データセットを指定し、データセットオプションの指定可*/
%put --------------------------------------------------;

	/*パラメータチェック*/
	%if %length(&input.) > 0 and (%length(&vname.) > 0 or %length(&char.) > 0) %then %put ERROR:パラメータinputと、vname・charは同時に指定できません。;

	/*区切り文字の選定*/
	%if %upcase( &tab. ) = Y %then %let dlm='09'x;
	%else                          %let dlm=',';

	filename in "%superq(infile)";

	/*変数名の自動取得(ヘッダー部分の読み込み)*/
	%let _vname=;
	%if %length(&input.)=0 and %length(&vname.)=0 %then %do;
		data _null_;

			infile in dsd lrecl=32767 truncover firstobs=&headerobs.;
			input vname $char32767.;

			/*半角スペースは削除するか、別の文字に置換すること*/
			if count( trim(vname) , ' ' ) > 0 then put 'ERROR:変数名に半角スペースが含まれています。削除か置換をしてください。';

			/* カンマをブランクに変換 */
			%if %upcase( &tab. ) ne Y %then %do;
				vname = translate( vname , ' ' , ',' );
			%end;

			vname_length = length(vname);
			if vname_length > 32000 then put "WARNING:ヘッダーの長さが大きいので注意して下さい。 ヘッダー長さ=" vname_length;

			/*変数名をマクロ変数化*/
			if _n_ = 1 then call symput( '_vname' , vname );
			stop;
		run;
		%let vname=&_vname.;
	%end;

	/*データの読込み*/
	data &outdata.;

		/*変数の並び順の調整*/
		%if %length(&vname.) > 0 %then %do;
			format &vname.;
		%end;

		infile in dsd dlm=&dlm. lrecl=1000000 missover firstobs=&firstobs.;

		%if %length(&char.) > 0 %then %do;
			length &char.;
		%end;

		input
			%if %length(&input.) > 0 %then %do;
				&input.
			%end;
			%else %do;
				&vname.
			%end;
		;

		/*入力形式を初期化*/
		informat _all_;
	run;

	filename in clear;

%mend read_text;